home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / linux / src / atalnx_3.lzh / atari-linux-0.01pl3 / atari / atacon.c next >
Encoding:
C/C++ Source or Header  |  1994-06-19  |  79.5 KB  |  2,746 lines

  1. /*
  2. **  linux/atari/atacon.c
  3. **
  4. **  Copyright (C) 1993 Bjoern Brauel and Roman Hodek
  5. **
  6. **
  7. ** This file is subject to the terms and conditions of the GNU General Public
  8. ** License.  See the file README.legal in the main directory of this archive
  9. ** for more details.
  10. */
  11.  
  12. #include <linux/types.h>
  13. #include <linux/fs.h>
  14. #include <linux/kernel.h>
  15. #include <linux/tty.h>
  16. #include <linux/console.h>
  17. #include <linux/string.h>
  18. #include <linux/timer.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/bootinfo.h>
  21. #include <linux/delay.h>
  22.  
  23. #include <linux/malloc.h>
  24. #include <linux/mm.h>
  25.  
  26. #include <linux/atarihw.h>
  27. #include <linux/atariints.h>
  28.  
  29. #include <asm/system.h>
  30.  
  31. /* The following symbols select what modes are supported. They should
  32.  * be settable by the user ("make config") later.
  33.  * True color (= 16 plane) mode isn't implemented yet!
  34.  */
  35. #define    CONFIG_ATARI_2PLANE
  36. #define    CONFIG_ATARI_4PLANE
  37. #define    CONFIG_ATARI_8PLANE
  38. #undef    CONFIG_ATARI_16PLANE
  39.  
  40. /* To do:
  41.  *
  42.  *  - Do proper Falcon video mode setting, analogous to the TT (but
  43.  *    much more and better modes possible!)
  44.  *  - Implement 16 plane mode.
  45.  *  - Do a backing store of characters and attributes on the screen
  46.  *    for conole switching (or will this be done in the device
  47.  *    independent part (console.c) ?)
  48.  *
  49.  */
  50.  
  51.  
  52. /*
  53. ** Macros
  54. */
  55.  
  56.  
  57. /* Define if the font contains all 256 characters (undefined: only
  58.  * 32..127 and 160..255, this is the font in font.c of the Amiga
  59.  * distribution)
  60.  */
  61.  
  62. #define    WHOLE_FONT
  63.  
  64. static unsigned long mem_req;
  65.  
  66. /* There is no support for fontwidth != 8 now!! (And I guess, it will
  67.  * never come; who needs such stuff??)
  68.  */
  69.  
  70. extern unsigned char
  71.     fontdata_8x16[], fontdata_8x8[];
  72.  
  73. extern int
  74.     fontheight_8x16, fontheight_8x8,
  75.     fontwidth_8x16, fontwidth_8x8;
  76.  
  77. extern char
  78.     fontname_8x16[], fontname_8x8[];
  79.  
  80.  
  81.  
  82.  
  83.  
  84. /* FONT_CNV does the character conversion necessary if the font
  85.  * doesn't contain all characters. It returns 0 if the characters is
  86.  * not in the font (WHOLE_FONT undefined).
  87.  * 
  88.  * If we have a full font, FONT_CNV has to do the jobs of translating
  89.  * the character to be printed according to the console's current
  90.  * translation table. This is just a quick hack to enable the
  91.  * different translations (normal, graphic, ...) that VT102 allows. It
  92.  * should really be done in console.c, where it is commented out
  93.  * currently, and I didn't want to interfere with the people
  94.  * maintaining that code.
  95.  *                                                             Roman
  96.  */
  97.  
  98. #ifndef WHOLE_FONT
  99.  
  100. #define    FONT_CNV(c) ({
  101.    int __rv = 1;
  102.    if ((c >= 32) && (c < 127))
  103.        /* lower half of charset -- normal ASCII */
  104.        c -=  32;
  105.     else if ((c >= 160) && (c < 255))
  106.         /* upper half of charset -- special characters */
  107.         c -= 64;
  108.     else
  109.         /* not defined in charset -- non-printable character */
  110.         __rv = 0;
  111.    __rv;
  112. })
  113.  
  114. #else
  115.  
  116. #define    FONT_CNV(c) ((c = conp->vc_translate[c]) != 0)
  117.  
  118. #endif
  119.  
  120.  
  121. /*
  122. ** Local Variables
  123. */
  124. struct tt_vid_type
  125. {
  126.     const char    *name;
  127.     ushort        xres;
  128.     ushort        yres;
  129.     ushort        depth;
  130. };
  131.  
  132. struct falcon_vid_type
  133. {
  134.     const char    *name;
  135. };
  136.  
  137. struct display;
  138.  
  139. struct display_switch {
  140.     void (*bmove)( register struct display *p, int sy, int sx, int dy,
  141.                    int dx, int height, int width);
  142.     void (*clear)( struct condata *conp, register struct display *p,
  143.                    int sy, int sx, int height, int width);
  144.     void (*putc)( struct condata *conp, struct display *p, int c,
  145.                   int y, int x, int mode );
  146.     void (*putcs)( struct condata *conp, struct display *p,
  147.                    const char *s, int count, int y, int x, int mode);
  148.     void (*rev_char)( struct display *display, int x, int y );
  149. };    
  150.  
  151. struct display
  152. {
  153.     ushort scr_height;            /* screens dimensions */
  154.     ushort scr_width;
  155.     ushort scr_depth;            /* # planes */
  156.     ushort bytes_per_row;        /* offset to one line below; if (scr_depth
  157.                                  * != 1), this is (scr_width / 8 *
  158.                                  * scr_depth)! */
  159.     ushort cursor_x;            /* current cursor position */
  160.     ushort cursor_y;
  161.  
  162.     ushort shiftmode;           /* display mode */
  163.  
  164.     ushort fgcol;               /* text colors */
  165.     ushort bgcol;
  166.  
  167.     u_char *bitplane;            /* pointer to display bitmap; planes
  168.                                  * are interleaved!
  169.                                  */
  170.     u_long *color_map;          /* XXX Not yet implemented XXX */
  171.  
  172.     u_char *fontdata;           /* Font associated to this display */
  173.     ushort fontheight;
  174.     ushort fontwidth;
  175.  
  176.     struct display_switch *dispsw;    /* pointers to depth specific
  177.                                      * functions
  178.                                      */
  179. };
  180.  
  181. static struct display disp[NR_CONSOLES];
  182.  
  183. static struct tt_vid_type tt_video_modes[TT_SHIFTER_NUMMODE] = {
  184.     { "stlow",   320 , 200 , 1 } ,            /* ST-Low */
  185.     { "stmid",   640 , 200 , 2 } ,            /* ST-Mid */
  186.     { "sthigh",  640 , 400 , 1 } ,            /* ST-High */
  187.     { "",        000 , 000 , 0 } ,            /* unused */
  188.     { "ttmid",   640 , 480 , 4 } ,            /* TT-Mid */
  189.     { "",        000 , 000 , 0 } ,            /* unused */
  190.     { "tthigh", 1280 , 960 , 1 } ,            /* TT-High */
  191.     { "ttlow",   320 , 480 , 8 } };            /* TT-Low */
  192.     
  193. static struct tt_vid_type falcon_video_modes[] = {
  194.     { "sthigh" }
  195. };
  196.  
  197. /* Default color maps for 4 and 2 plane modes. These use the PC-ish
  198.  * assignment (the low 3 bits turn each RBG channel on/off, the 4th
  199.  * bit is intensity). Currently, 8 plane mode uses the 4 plane color
  200.  * table, too.
  201.  */
  202.  
  203. u_short default_16_colors[16] = {
  204.     0x000,    /* black */
  205.     0x00c,    /* blue */
  206.     0x0c0,    /* green */
  207.     0x0cc,    /* cyan */
  208.     0xc00,    /* red */
  209.     0xc0c,    /* magenta */
  210.     0xcc0,    /* brown */
  211.     0xccc,    /* light gray */
  212.     0x888,    /* gray */
  213.     0x00f,    /* light blue */
  214.     0x0f0,    /* light green */
  215.     0x0ff,    /* light cyan */
  216.     0xf00,    /* light red */
  217.     0xf0f,    /* light magenta */
  218.     0xff0,    /* light brown */
  219.     0xfff    /* white */
  220. };
  221.  
  222. /* The 4 colors of 2 plane mode are used as a grey scale to implement
  223.  * the vc_intensity == 0 or == 2 modes.
  224.  */
  225.  
  226. u_short default_4_colors[4] = {
  227.     0x000,    /* black */
  228.     0xccc,    /* light gray */
  229.     0x888,    /* gray */
  230.     0xfff    /* white */
  231. };
  232.  
  233.         
  234. static int cursor_drawn = 0;
  235.  
  236. static int atacon_default_font = -1;
  237. static int atacon_default_shiftmode = -1;
  238.  
  239.  
  240. #undef CURSOR_DELAY_TIMER
  241. #define    CURSOR_DELAY_VBL
  242.  
  243. #ifdef CURSOR_DELAY_TIMER
  244.  
  245. /* Time to elapse before the cursor is really drawn, in jiffies */
  246. #define    CURSOR_DRAW_DELAY    3
  247.  
  248. #define    CURSOR_UNDRAWN()                        \
  249.     do {                                        \
  250.         del_timer( &atacon_cursor_timer );        \
  251.         cursor_drawn = 0;                        \
  252.     } while(0)
  253.  
  254. #endif
  255.  
  256. #ifdef CURSOR_DELAY_VBL
  257.  
  258. /* The VBL cursor looks much better than the timer cursor, because the
  259.  * inverting is done only in the VBlank time, when nothing is
  260.  * displayed. This avoids flickering when moving the cursor fastly. I
  261.  * guess the timer cursor will go away in futuere.
  262.  */
  263.  
  264. /* Time to elapse before the cursor is really drawn, in VBL units
  265.  * (60 Hz: 17 ms, 72 Hz: 14 ms)
  266.  */
  267. #define    CURSOR_DRAW_DELAY    2
  268.  
  269. /* # VBL ints between cursor state changes */
  270. #define    DEFAULT_CURSOR_BLINK_RATE    42
  271.  
  272. static int        vbl_cursor_cnt = 0;
  273. static int        cursor_on = 0;
  274. static int        cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE;
  275.  
  276. #define    CURSOR_UNDRAWN()                        \
  277.     do {                                        \
  278.         vbl_cursor_cnt = 0;                        \
  279.         cursor_drawn = 0;                        \
  280.     } while(0)
  281.  
  282. #endif
  283.  
  284.  
  285. /***************************** Prototypes *****************************/
  286.  
  287. static void detect_video( ushort *yres, ushort *xres, ushort *depth, ushort
  288.                           *shiftmode );
  289. static int shifter_init( u_long adr);
  290. static int atacon_init( struct condata *conp, long mem_start);
  291. static int atacon_deinit( struct condata *conp);
  292. static __inline__ void *mymemclear_small( void * s, size_t count);
  293. static __inline__ void *mymemclear( void * s, size_t count);
  294. static __inline__ void *mymemmove( void * d, void * s, size_t count);
  295. static __inline__ void memclear_4p_col( void *d, size_t h, u_long val,
  296.                                         u_short bpr );
  297. static __inline__ void memset_even_4p( void *d, size_t count, u_long val1,
  298.                                        u_long val2 );
  299. static __inline__ void memmove_4p_col( void *d, void *s, u_short h, u_short
  300.                                        bpr );
  301. static __inline__ unsigned long expand4l( unsigned char c );
  302. static __inline__ void expand4dl( unsigned char c, unsigned long *ret1,
  303.                                   unsigned long *ret2 );
  304. static __inline__ unsigned long dup4l( unsigned char c );
  305. static __inline__ void memclear_8p_col( void *d, size_t h, u_long val1,
  306.                                         u_long val2, u_short bpr );
  307. static __inline__ void memset_even_8p( void *d, size_t count, u_long val1,
  308.                                        u_long val2, u_long val3, u_long
  309.                                        val4 );
  310. static __inline__ void memmove_8p_col( void *d, void *s, u_short h, u_short
  311.                                        bpr );
  312. static __inline__ void expand8dl( unsigned char c, u_long *ret1, u_long
  313.                                   *ret2 );
  314. static __inline__ void expand8ql( unsigned char c, unsigned long *ret1,
  315.                                   unsigned long *ret2, unsigned long *ret3,
  316.                                   unsigned long *ret4 );
  317. static __inline__ void memclear_2p_col( void *d, size_t h, u_short val,
  318.                                         u_short bpr );
  319. static __inline__ void memset_even_2p( void *d, size_t count, u_long val );
  320. static __inline__ void memmove_2p_col( void *d, void *s, u_short h, u_short
  321.                                        bpr );
  322. static __inline__ unsigned short expand2w( unsigned char c );
  323. static __inline__ unsigned short dup2w( unsigned char c );
  324. static int atacon_bmove( struct condata *conp, int sy, int sx, int dy, int
  325.                          dx, int height, int width);
  326. static int atacon_clear( struct condata *conp, int sy, int sx, int height,
  327.                          int width);
  328. static int atacon_putc( struct condata *conp, int c, int y, int x, int
  329.                         mode);
  330. static int atacon_putcs( struct condata *conp, const char *s, int count,
  331.                          int y, int x, int mode);
  332. static int atacon_scroll( struct condata *conp, int t, int b, int dir, int
  333.                           count);
  334. static int atacon_switch( struct condata *conp);
  335. static void atacon_bmove_1_plane( register struct display *p, int sy, int
  336.                                   sx, int dy, int dx, int height, int
  337.                                   width);
  338. static void atacon_clear_1_plane( struct condata *conp, register struct
  339.                                   display *p, int sy, int sx, int height,
  340.                                   int width );
  341. static void atacon_putc_1_plane( struct condata *conp, struct display *p,
  342.                                  int c, int y, int x, int mode);
  343. static void atacon_putcs_1_plane( struct condata *conp, struct display *p,
  344.                                   const char *s, int count, int y, int x,
  345.                                   int mode);
  346. static void atacon_rev_char_1_plane( struct display *display, int x, int y
  347.                                      );
  348. #ifdef CONFIG_ATARI_2PLANE
  349. static void atacon_bmove_2_plane( register struct display *p, int sy, int
  350.                                   sx, int dy, int dx, int height, int
  351.                                   width);
  352. static void atacon_clear_2_plane( struct condata *conp, register struct
  353.                                   display *p, int sy, int sx, int height,
  354.                                   int width );
  355. static void atacon_putc_2_plane( struct condata *conp, struct display *p,
  356.                                  int c, int y, int x, int mode);
  357. static void atacon_putcs_2_plane( struct condata *conp, struct display *p,
  358.                                   const char *s, int count, int y, int x,
  359.                                   int mode);
  360. static void atacon_rev_char_2_plane( struct display *display, int x, int y
  361.                                      );
  362. #endif
  363. #ifdef CONFIG_ATARI_4PLANE
  364. static void atacon_bmove_4_plane( register struct display *p, int sy, int
  365.                                   sx, int dy, int dx, int height, int
  366.                                   width);
  367. static void atacon_clear_4_plane( struct condata *conp, register struct
  368.                                   display *p, int sy, int sx, int height,
  369.                                   int width );
  370. static void atacon_putc_4_plane( struct condata *conp, struct display *p,
  371.                                  int c, int y, int x, int mode);
  372. static void atacon_putcs_4_plane( struct condata *conp, struct display *p,
  373.                                   const char *s, int count, int y, int x,
  374.                                   int mode);
  375. static void atacon_rev_char_4_plane( struct display *display, int x, int y
  376.                                      );
  377. #endif
  378. #ifdef CONFIG_ATARI_8PLANE
  379. static void atacon_bmove_8_plane( register struct display *p, int sy, int
  380.                                   sx, int dy, int dx, int height, int
  381.                                   width);
  382. static void atacon_clear_8_plane( struct condata *conp, register struct
  383.                                   display *p, int sy, int sx, int height,
  384.                                   int width );
  385. static void atacon_putc_8_plane( struct condata *conp, struct display *p,
  386.                                  int c, int y, int x, int mode);
  387. static void atacon_putcs_8_plane( struct condata *conp, struct display *p,
  388.                                   const char *s, int count, int y, int x,
  389.                                   int mode);
  390. static void atacon_rev_char_8_plane( struct display *display, int x, int y
  391.                                      );
  392. #endif
  393. #ifdef CURSOR_DELAY_TIMER
  394. static void atacon_curtimfunc( unsigned long _disp );
  395. #endif
  396. #ifdef CURSOR_DELAY_VBL
  397. static void atacon_vbl_handler( struct intframe *fp, void *dummy );
  398. #endif
  399. static int atacon_cursor( struct condata *conp, int mode);
  400.  
  401. /************************* End of Prototypes **************************/
  402.  
  403.  
  404. struct display_switch
  405.     dispsw_1_plane = {
  406.         atacon_bmove_1_plane, atacon_clear_1_plane, atacon_putc_1_plane,
  407.         atacon_putcs_1_plane, atacon_rev_char_1_plane
  408.     }
  409. #ifdef CONFIG_ATARI_2PLANE
  410.     , dispsw_2_plane = {
  411.         atacon_bmove_2_plane, atacon_clear_2_plane, atacon_putc_2_plane,
  412.         atacon_putcs_2_plane, atacon_rev_char_2_plane
  413.     }
  414. #endif
  415. #ifdef CONFIG_ATARI_4PLANE
  416.     , dispsw_4_plane = {
  417.         atacon_bmove_4_plane, atacon_clear_4_plane, atacon_putc_4_plane,
  418.         atacon_putcs_4_plane, atacon_rev_char_4_plane
  419.     }
  420. #endif
  421. #ifdef CONFIG_ATARI_8PLANE
  422.     , dispsw_8_plane = {
  423.         atacon_bmove_8_plane, atacon_clear_8_plane, atacon_putc_8_plane,
  424.         atacon_putcs_8_plane, atacon_rev_char_8_plane
  425.     }
  426. #endif
  427. #ifdef CONFIG_ATARI_16PLANE
  428.     , dispsw_16_plane = {
  429.         atacon_bmove_16_plane, atacon_clear_16_plane, atacon_putc_16_plane,
  430.         atacon_putcs_16_plane, atacon_rev_char_16_plane
  431.     }
  432. #endif
  433. ;
  434.     
  435.  
  436.  
  437.  
  438. #ifdef CURSOR_DELAY_TIMER
  439.  
  440. static struct timer_list atacon_cursor_timer = { NULL,0,0,atacon_curtimfunc };
  441.  
  442. #endif
  443.  
  444.  
  445. /* ================================================================= */
  446. /*                        Initialization Functions                   */
  447. /* ================================================================= */
  448.  
  449.  
  450. /* atari_video_setup() processes command line options and stores them
  451.  * in atacon_default_font and atacon_default_shiftmode. Their validity
  452.  * is checked later.
  453.  */
  454.  
  455. void atari_video_setup( char *options, int *ints )
  456.  
  457. {    char    *this_opt;
  458.     int        i, max;
  459.  
  460.     if (!options || !*options)
  461.         return;
  462.     
  463.     for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
  464.  
  465.         if (!*this_opt) continue;
  466.         
  467.         if (!strcmp (this_opt, "f8x8")) {
  468.             atacon_default_font = 8;
  469.         }
  470.         else if (!strcmp (this_opt, "f8x16")) {
  471.             atacon_default_font = 16;
  472.         }
  473.         else {
  474.  
  475.             if (boot_info.bi_atari.model == ATARI_TT) {
  476.                 max = sizeof(tt_video_modes)/sizeof(tt_video_modes[0]);
  477.                 for (i = 0; i < max; i++) {
  478.                     if (!strcmp( this_opt, tt_video_modes[i].name )) {
  479.                         atacon_default_shiftmode = i;
  480.                         break;
  481.                     }
  482.                 }
  483.             }
  484.             else {
  485.                 max = sizeof(falcon_video_modes)/sizeof(falcon_video_modes[0]);
  486.                 for (i = 0; i < max; i++) {
  487.                     if (!strcmp( this_opt, falcon_video_modes[i].name )) {
  488.                         atacon_default_shiftmode = i;
  489.                         break;
  490.                     }
  491.                 }
  492.             }
  493.  
  494.             if (i == max)
  495.                 printk( "atari_video_setup: Unknown option %s\n", this_opt );
  496.         }
  497.     }
  498. }
  499.  
  500.  
  501. /* detect_video() selects a screen size/depth pair and programs the
  502.  * hardware for this mode. It chooses the shift mode given on the
  503.  * command line, if this is possible with the connected monitor type.
  504.  * Else is falls back to a default mode for the monitor.
  505.  * Note that this isn't implemented for the Falcon yet, because there
  506.  * are many, many possibilities. The Falcon uses always St High mode
  507.  * for now. To be re-worked.
  508.  */
  509.  
  510. static void detect_video( ushort *yres, ushort *xres, ushort *depth,
  511.                           ushort *shiftmode )
  512.  
  513. {    static int detected = 0;
  514.     
  515.     if (boot_info.bi_atari.model == ATARI_TT) {
  516.  
  517.         int        mono_moni, i;
  518.  
  519.         if (!detected) {
  520.             /* Determine the connected monitor: The DMA sound must be
  521.              * disabled before reading the MFP GPIP, because the Sound
  522.              * Done Signal and the Monochrome Detect are XORed together!
  523.              */
  524.  
  525.             tt_dmasnd.ctrl = DMASND_CTRL_OFF;
  526.             udelay( 20 );    /* wait a while for things to settle down */
  527.             mono_moni = (mfp.par_dt_reg & 0x80) == 0;
  528.  
  529.             /* If the command line shift mode isn't compatible with the
  530.              * monitor type, reset it to -1. A default mode will be
  531.              * selected then below.
  532.              */
  533.  
  534.             if (atacon_default_shiftmode != -1)
  535.                 if ((mono_moni && atacon_default_shiftmode != TT_HIGH) ||
  536.                     (!mono_moni && atacon_default_shiftmode == TT_HIGH))
  537.                     atacon_default_shiftmode = -1;
  538.         
  539.             /* Set a default shift mode, if none was given on the command
  540.              * line or that isn't possible.
  541.              */
  542.             if (atacon_default_shiftmode == -1)
  543.                 atacon_default_shiftmode = mono_moni ? TT_HIGH :
  544. #ifdef CONFIG_ATARI_4PLANE
  545.                     ST_HIGH;
  546. #else
  547.                     TT_MID;
  548. #endif
  549.  
  550.             /* Initialize the shift mode, palette bank = 0 */
  551.             shifter_tt.tt_shiftmode = atacon_default_shiftmode << 8;
  552.  
  553.             /* Set up the colormap registers */
  554.             if (tt_video_modes[atacon_default_shiftmode].depth >= 4) {
  555.                 for( i = 0; i < 16; ++i )
  556.                     tt_palette[i] = default_16_colors[i];
  557.             }
  558.             else if (tt_video_modes[atacon_default_shiftmode].depth == 2) {
  559.                 for( i = 0; i < 4; ++i )
  560.                     tt_palette[i] = default_4_colors[i];
  561.             }
  562.             else /* depth == 1 */ {
  563.                 tt_palette[254] = 0x000; /* black */
  564.                 tt_palette[255] = 0xfff; /* white */
  565.             }
  566.             
  567.             detected = 1;
  568.         }
  569.         
  570.         *yres  = tt_video_modes[atacon_default_shiftmode].yres;
  571.         *xres  = tt_video_modes[atacon_default_shiftmode].xres;
  572.         *depth = tt_video_modes[atacon_default_shiftmode].depth;
  573.         *shiftmode = atacon_default_shiftmode;
  574.     }
  575.     else if (boot_info.bi_atari.model == ATARI_FALCON) {
  576.  
  577.         *yres  = 400;
  578.         *xres  = 640;
  579.         *depth = 1;
  580.  
  581.     }
  582.  }
  583.  
  584. static int shifter_init(u_long adr)
  585.  {
  586. /* Setup Screen Memory */
  587.   shifter.bas_hi=(u_char)((adr & 0xff0000) >> 16);
  588.   shifter.bas_md=(u_char)((adr & 0x00ff00) >> 8);
  589.   shifter.bas_lo=(u_char)(adr & 0x0000ff);
  590.   return 0;
  591.  }
  592.  
  593.  
  594. static int atacon_init(struct condata *conp, long mem_start)
  595. {
  596.     int unit = conp - vc_cons;    
  597.  
  598.     /* set up the display defaults */
  599.     detect_video( &disp[unit].scr_height, &disp[unit].scr_width,
  600.                   &disp[unit].scr_depth, &disp[unit].shiftmode );
  601.  
  602.     /* If no font was selected on the command line, choose a default
  603.      * font: This is 8x8 if the display has less than 400 lines, 8x16
  604.      * else.
  605.      */
  606.     if (atacon_default_font == -1)
  607.         atacon_default_font = (disp[unit].scr_height < 400) ? 8 : 16;
  608.  
  609.     if (atacon_default_font == 16) {
  610.         disp[unit].fontdata   = fontdata_8x16;
  611.         disp[unit].fontheight = fontheight_8x16;
  612.         disp[unit].fontwidth  = fontwidth_8x16;
  613.     }
  614.     else if (atacon_default_font == 8) {
  615.         disp[unit].fontdata   = fontdata_8x8;
  616.         disp[unit].fontheight = fontheight_8x8;
  617.         disp[unit].fontwidth  = fontwidth_8x8;
  618.     }
  619.     else
  620.         panic( "atacon_init: No support for fontheight %d.\n",
  621.                atacon_default_font );
  622.  
  623.     disp[unit].bytes_per_row = (disp[unit].scr_width >> 3) *
  624.                                disp[unit].scr_depth;
  625.     disp[unit].cursor_x = 0;
  626.     disp[unit].cursor_y = 0;
  627.     
  628.     if (disp[unit].scr_depth == 1) {
  629.         disp[unit].dispsw = &dispsw_1_plane;
  630.         disp[unit].fgcol = 1;
  631.         disp[unit].bgcol = 0;
  632.     }
  633. #ifdef CONFIG_ATARI_2PLANE
  634.     else if (disp[unit].scr_depth == 2) {
  635.         disp[unit].dispsw = &dispsw_2_plane;
  636.         disp[unit].fgcol = 3;
  637.         disp[unit].bgcol = 0;
  638.     }
  639. #endif
  640. #ifdef CONFIG_ATARI_4PLANE
  641.     else if (disp[unit].scr_depth == 4) {
  642.         disp[unit].dispsw = &dispsw_4_plane;
  643.         disp[unit].fgcol = 7;
  644.         disp[unit].bgcol = 0;
  645.     }
  646. #endif
  647. #ifdef CONFIG_ATARI_8PLANE
  648.     else if (disp[unit].scr_depth == 8) {
  649.         disp[unit].dispsw = &dispsw_8_plane;
  650.         disp[unit].fgcol = 7;
  651.         disp[unit].bgcol = 0;
  652.     }
  653. #endif
  654. #ifdef CONFIG_ATARI_16PLANE
  655.     else if (disp[unit].scr_depth == 16) {
  656.         disp[unit].dispsw = &dispsw_16_plane;
  657.         disp[unit].fgcol = 0xbbbbbb;
  658.         disp[unit].bgcol = 0;
  659.     }
  660. #endif
  661.     else
  662.         panic( "atacon_init: %d planes not supported.\n",
  663.                disp[unit].scr_depth );
  664.     
  665.     conp->vc_cols = disp[unit].scr_width / disp[unit].fontwidth;
  666.     conp->vc_rows = disp[unit].scr_height / disp[unit].fontheight;
  667.  
  668.     mem_req = (disp[unit].scr_width/8)*disp[unit].scr_height*
  669.               disp[unit].scr_depth;
  670.     /* locate the bitplane */
  671.     mem_start = (mem_start + 7) & ~7; /* round up */
  672.     disp[unit].bitplane = (u_char *)mem_start;
  673.     mem_start += mem_req;
  674.     mymemclear( disp[unit].bitplane, mem_req );
  675.  
  676.     shifter_init( (u_long)(disp[unit].bitplane) );
  677.     
  678.  
  679. #ifdef CURSOR_DELAY_VBL
  680.     add_isr( IRQ4, atacon_vbl_handler, 0, NULL );
  681. #endif
  682.     
  683.     return mem_start;
  684. }
  685.  
  686. static int atacon_deinit (struct condata *conp)
  687. {
  688.     return 0;
  689. }
  690.  
  691.  
  692. /* ================================================================= */
  693. /*                      Utility Assembler Functions                  */
  694. /* ================================================================= */
  695.  
  696.  
  697. /* ====================================================================== */
  698.  
  699. /* Those of a delicate disposition might like to skip the next couple of
  700.  * pages.
  701.  *
  702.  * These functions are drop in replacements for memmove and
  703.  * memset(_, 0, _). However their five instances add at least a kilobyte
  704.  * to the object file. You have been warned.
  705.  *
  706.  * Not a great fan of assembler for the sake of it, but I think
  707.  * that these routines are at least 10 times faster than their C
  708.  * equivalents for large blits, and thats important to the lowest level of
  709.  * a graphics driver. Question is whether some scheme with the blitter
  710.  * would be faster. I suspect not for simple text system - not much
  711.  * asynchronisity.
  712.  *
  713.  * Code is very simple, just gruesome expansion. Basic strategy is to
  714.  * increase data moved/cleared at each step to 16 bytes to reduce
  715.  * instruction per data move overhead. movem might be faster still
  716.  * For more than 15 bytes, we try to align the write direction on a
  717.  * longword boundary to get maximum speed. This is even more gruesome.
  718.  * Unaligned read/write used requires 68020+ - think this is a problem?
  719.  *
  720.  * Sorry!
  721.  */
  722.  
  723. /* ++roman: I've optimized Robert's original versions in some minor
  724.  * aspects, e.g. moveq instead of movel, let gcc choose the registers,
  725.  * use movem in some places...
  726.  * For other modes than 1 plane, lots of more such assembler functions
  727.  * were needed (e.g. the ones using movep or expanding color values).
  728.  */
  729.  
  730.  
  731. static __inline__ void *mymemclear_small(void * s, size_t count)
  732. {
  733.     long tmp1, tmp2, tmp3, tmp4;
  734.     
  735.     if (!count) return(0);
  736.     
  737.     __asm__ __volatile__
  738.        ("moveq  #0,%2 ; movel  %2,%3 ; movel  %2,%4 ; movel  %2,%5\n\t"
  739.         "addl   %1,%0\n\t"
  740.         "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
  741.      "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
  742.      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
  743.      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
  744.      "1: subql  #1,%1 ; jcs 3f\n\t"
  745.      "2: moveml %2/%3/%4/%5,%0@-\n\t"
  746.         "dbra %1,2b\n\t"
  747.      "3:"
  748.         : "=a" (s), "=d" (count), "=d" (tmp1), "=d" (tmp2), "=d" (tmp3), "=d" (tmp4)
  749.         : "0" (s), "1" (count)
  750.        );
  751.  
  752.    return(0);              
  753. }
  754.  
  755. static __inline__ void *mymemclear(void * s, size_t count)
  756. {
  757.     if (!count)
  758.         return(0);
  759.     
  760.     else if (count < 16) {
  761.         long tmp;
  762.         __asm__ __volatile__
  763.         ("moveq  #0,%2\n\t"
  764.          "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0@+\n\t"
  765.        "1:lsrl   #1,%1 ; jcc 1f ; movew %2,%0@+\n\t"
  766.        "1:lsrl   #1,%1 ; jcc 1f ; movel %2,%0@+\n\t"
  767.        "1:lsrl   #1,%1 ; jcc 1f ; movel %2,%0@+ ; movel %2,%0@+\n\t"
  768.        "1:"
  769.          : "=a" (s), "=d" (count), "=d" (tmp)
  770.          : "0" (s), "1" (count)
  771.         );
  772.     }
  773.     
  774.     else {
  775.         long    tmp;
  776.         __asm__ __volatile__
  777.         ("movel %1,%2\n\t"
  778.          "lsrl   #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t"
  779.          "lsrl   #1,%2 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
  780.          "clrw   %0@+  ; subqw  #2,%1 ; jra 2f\n\t"
  781.       "1: lsrl   #1,%2 ; jcc 2f\n\t"
  782.          "clrw   %0@+  ; subqw  #2,%1\n\t"
  783.       "2: movew %1,sp@-; moveq #0,%2 ; lsrl #2,%1 ; jeq 6f\n\t"
  784.          "lsrl   #1,%1 ; jcc 3f ; movel %2,%0@+\n\t"        
  785.       "3: lsrl   #1,%1 ; jcc 4f ; movel %2,%0@+ ; movel %2,%0@+\n\t"
  786.       "4: subql  #1,%1 ; jcs 6f\n\t"
  787.       "5: movel %2,%0@+; movel %2,%0@+ ; movel %2,%0@+ ; movel %2,%0@+\n\t"
  788.          "dbra %1,5b   ; subl #65536,%1; jcc 5b\n\t"
  789.       "6: movew sp@+,%1; btst #1,%1 ; jeq 7f ; movew %2,%0@+\n\t"
  790.       "7:              ; btst #0,%1 ; jeq 8f ; moveb %2,%0@+\n\t"
  791.       "8:"
  792.          : "=a" (s), "=d" (count), "=d" (tmp)
  793.          : "0" (s), "1" (count)
  794.         );
  795.     }
  796.     
  797.     return(0);              
  798. }
  799.  
  800. static __inline__ void *mymemmove(void * d, void * s, size_t count)
  801. {
  802.     if (d < s) {
  803.         if (count < 16) {
  804.             __asm__ __volatile__
  805.        ("lsrl   #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t"
  806.       "1:lsrl   #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t"
  807.       "1:lsrl   #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t"
  808.       "1:lsrl   #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
  809.       "1:"
  810.         : "=a" (d), "=a" (s), "=d" (count)
  811.         : "0" (d), "1" (s), "2" (count)
  812.        );
  813.        } else {
  814.            long tmp;
  815.            __asm__ __volatile__
  816.        ("movel  %0,%3\n\t"
  817.         "lsrl   #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t"
  818.         "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
  819.         "movew  %1@+,%0@+  ; subqw  #2,%2 ; jra 2f\n\t"
  820.      "1: lsrl   #1,%3 ; jcc 2f\n\t"
  821.         "movew  %1@+,%0@+  ; subqw  #2,%2\n\t"
  822.      "2: movew  %2,sp@-; lsrl #2,%2 ; jeq 6f\n\t"
  823.         "lsrl   #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t"        
  824.      "3: lsrl   #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
  825.      "4: subql  #1,%2 ; jcs 6f\n\t"
  826.      "5: movel  %1@+,%0@+;movel %1@+,%0@+\n\t"
  827.         "movel  %1@+,%0@+;movel %1@+,%0@+\n\t"
  828.         "dbra   %2,5b ; subl #65536,%2; jcc 5b\n\t"
  829.      "6: movew sp@+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t"
  830.      "7:              ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t"
  831.      "8:"
  832.         : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
  833.         : "0" (d), "1" (s), "2" (count)
  834.        );
  835.       }
  836.    } else {
  837.     if (count < 16) {
  838.         __asm__ __volatile__
  839.        ("addal  %2,%0 ; addal %2,%1\n\t"
  840.         "lsrl   #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t"
  841.       "1:lsrl   #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t"
  842.       "1:lsrl   #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t"
  843.       "1:lsrl   #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
  844.       "1:"
  845.         : "=a" (d), "=a" (s), "=d" (count)
  846.         : "0" (d), "1" (s), "2" (count)
  847.        );
  848.       } else {
  849.           long tmp;
  850.           __asm__ __volatile__
  851.        ("addal  %2,%0 ; addal %2,%1; movel %0,%3\n\t"
  852.         "lsrl   #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t"
  853.         "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
  854.         "movew  %1@-,%0@-  ; subqw  #2,%2 ; jra 2f\n\t"
  855.      "1: lsrl   #1,%3 ; jcc 2f\n\t"
  856.         "movew  %1@-,%0@-  ; subqw  #2,%2\n\t"
  857.      "2: movew %2,sp@-; lsrl #2,%2 ; jeq 6f\n\t"
  858.         "lsrl   #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t"        
  859.      "3: lsrl   #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
  860.      "4: subql  #1,%2 ; jcs 6f\n\t"
  861.           "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t"
  862.              "movel %1@-,%0@-;movel %1@-,%0@-\n\t"
  863.              "dbra %2,5b ; subl #65536,%2; jcc 5b\n\t"
  864.      "6: movew sp@+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t"
  865.      "7:              ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t"
  866.      "8:"
  867.         : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
  868.         : "0" (d), "1" (s), "2" (count)
  869.        );
  870.       }
  871.    }
  872.    return(0);              
  873. }
  874.  
  875. /* Sets the bytes in the visible column at d, height h, to the value
  876.  * val for a 4 plane screen. The the bis of the color in 'color' are
  877.  * moved (8 times) to the respective bytes. This means:
  878.  *
  879.  * for( h times; d += bpr )
  880.  *   *d     = (color & 1) ? 0xff : 0;
  881.  *   *(d+2) = (color & 2) ? 0xff : 0;
  882.  *   *(d+4) = (color & 4) ? 0xff : 0;
  883.  *   *(d+6) = (color & 8) ? 0xff : 0;
  884.  */
  885.  
  886. static __inline__ void memclear_4p_col( void *d, size_t h,
  887.                                         u_long val, u_short bpr  )
  888.  
  889. {
  890.     __asm__ __volatile__
  891.         ( "subql  #1,%1\n\t"
  892.        "1: movepl %4,%0@(0)\n\t"
  893.           "addaw  %5,%0\n\t"
  894.           "dbra      %1,1b"
  895.           : "=a" (d), "=d" (h)
  896.           : "0" (d), "1" (h), "d" (val), "r" (bpr)
  897.         );
  898. }
  899.  
  900. /* Sets a 4 plane region from 'd', length 'count' bytes, to the color
  901.  * in val1/val2. 'd' has to be an even address and count must be divisible
  902.  * by 8, because only whole words and all planes are accessed. I.e.:
  903.  *
  904.  * for( count/8 times )
  905.  *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
  906.  *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
  907.  *   *(d+4) = *(d+5) = (color & 4) ? 0xff : 0;
  908.  *   *(d+6) = *(d+7) = (color & 8) ? 0xff : 0;
  909.  */
  910.  
  911. static __inline__ void memset_even_4p( void *d, size_t count,
  912.                                        u_long val1, u_long val2 )
  913.  
  914. {    
  915.     __asm__ __volatile__
  916.         ( "lsrl   #3,%1\n\t"
  917.           "subql  #1,%1\n\t"
  918.        "1: movel  %4,%0@+\n\t"
  919.           "movel  %5,%0@+\n\t"
  920.           "dbra      %1,1b\n\t"
  921.           "subl      #65536,%1\n\t"
  922.           "jcc      1b"
  923.           : "=a" (d), "=d" (count)
  924.           : "0" (d), "1" (count), "d" (val1), "d" (val2)
  925.         );
  926. }
  927.  
  928. /* Copies a 4 plane column from 's', height 'h', to 's'. */
  929.  
  930. static __inline__ void memmove_4p_col( void *d, void *s, u_short h,
  931.                                        u_short bpr )
  932.  
  933. {    unsigned long    tmp;
  934.  
  935.     __asm__ __volatile__
  936.         ( "subqw  #1,%2\n\t"
  937.        "1: movepl %0@(0),%3\n\t"
  938.           "movepl %3,%1@(0)\n\t"
  939.           "addaw  %7,%0\n\t"
  940.           "addaw  %7,%1\n\t"
  941.           "dbra   %2,1b"
  942.           : "=a" (s), "=a" (d), "=d" (h), "=&d" (tmp)
  943.           : "0" (s), "1" (d), "2" (h), "d" (bpr)
  944.         );
  945. }
  946.  
  947.  
  948. /* This expands a 4 bit color into a long for movepl (4 plane) operations. */
  949.  
  950. static __inline__ unsigned long expand4l( unsigned char c )
  951.  
  952. {    unsigned long    rv;
  953.     
  954.     __asm__ __volatile__
  955.         ( "lsrb     #1,%2\n\t"
  956.           "scs     %0\n\t"
  957.           "lsll     #8,%0\n\t"
  958.           "lsrb     #1,%2\n\t"
  959.           "scs     %0\n\t"
  960.           "lsll     #8,%0\n\t"
  961.           "lsrb     #1,%2\n\t"
  962.           "scs     %0\n\t"
  963.           "lsll     #8,%0\n\t"
  964.           "lsrb     #1,%2\n\t"
  965.           "scs     %0\n\t"
  966.           : "=&d" (rv), "=d" (c)
  967.           : "1" (c)
  968.         );
  969.     return( rv );
  970. }
  971.  
  972. /* This expands a 4 bit color into two longs for two movel operations
  973.  * (4 planes).
  974.  */
  975.  
  976. static __inline__ void expand4dl( unsigned char c, unsigned long *ret1,
  977.                                unsigned long *ret2 )
  978.  
  979. {    unsigned long    rv1, rv2;
  980.     
  981.     __asm__ __volatile__
  982.         ( "lsrb     #1,%3\n\t"
  983.           "scs     %0\n\t"
  984.           "extw     %0\n\t"
  985.           "swap     %0\n\t"
  986.           "lsrb     #1,%3\n\t"
  987.           "scs     %0\n\t"
  988.           "extw     %0\n\t"
  989.           "lsrb     #1,%3\n\t"
  990.           "scs     %1\n\t"
  991.           "extw     %1\n\t"
  992.           "swap     %1\n\t"
  993.           "lsrb     #1,%3\n\t"
  994.           "scs   %1\n\t"
  995.           "extw     %1"
  996.           : "=&d" (rv1), "=&d" (rv2), "=d" (c)
  997.           : "2" (c)
  998.         );
  999.     *ret1 = rv1;
  1000.     *ret2 = rv2;
  1001. }
  1002.  
  1003.  
  1004. /* This duplicates a byte 4 times into a long. */
  1005.  
  1006. static __inline__ unsigned long dup4l( unsigned char c )
  1007.  
  1008. {    ushort    tmp;
  1009.     ulong    rv;
  1010.  
  1011.     __asm__ __volatile__
  1012.         ( "moveb  %2,%0\n\t"
  1013.           "lslw   #8,%0\n\t"
  1014.           "moveb  %2,%0\n\t"
  1015.           "movew  %0,%1\n\t"
  1016.           "swap   %0\n\t"
  1017.           "movew  %1,%0"
  1018.           : "=&d" (rv), "=d" (tmp)
  1019.           : "d" (c)
  1020.         );
  1021.  
  1022.     return( rv );
  1023. }
  1024.  
  1025.  
  1026. /* Sets the bytes in the visible column at d, height h, to the value
  1027.  * val1,val2 for a 8 plane screen. The the bis of the color in 'color' are
  1028.  * moved (8 times) to the respective bytes. This means:
  1029.  *
  1030.  * for( h times; d += bpr )
  1031.  *   *d      = (color & 1) ? 0xff : 0;
  1032.  *   *(d+2)  = (color & 2) ? 0xff : 0;
  1033.  *   *(d+4)  = (color & 4) ? 0xff : 0;
  1034.  *   *(d+6)  = (color & 8) ? 0xff : 0;
  1035.  *   *(d+8)  = (color & 16) ? 0xff : 0;
  1036.  *   *(d+10) = (color & 32) ? 0xff : 0;
  1037.  *   *(d+12) = (color & 64) ? 0xff : 0;
  1038.  *   *(d+14) = (color & 128) ? 0xff : 0;
  1039.  */
  1040.  
  1041. static __inline__ void memclear_8p_col( void *d, size_t h, u_long val1,
  1042.                                         u_long val2, u_short bpr  )
  1043.  
  1044. {
  1045.     __asm__ __volatile__
  1046.         ( "subql  #1,%1\n\t"
  1047.        "1: movepl %4,%0@(0)\n\t"
  1048.           "movepl %5,%0@(8)\n\t"
  1049.           "addaw  %6,%0\n\t"
  1050.           "dbra      %1,1b"
  1051.           : "=a" (d), "=d" (h)
  1052.           : "0" (d), "1" (h), "d" (val1), "d" (val2), "r" (bpr)
  1053.         );
  1054. }
  1055.  
  1056. /* Sets a 8 plane region from 'd', length 'count' bytes, to the color
  1057.  * val1..val4. 'd' has to be an even address and count must be divisible
  1058.  * by 16, because only whole words and all planes are accessed. I.e.:
  1059.  *
  1060.  * for( count/16 times )
  1061.  *   *d      = *(d+1)  = (color & 1) ? 0xff : 0;
  1062.  *   *(d+2)  = *(d+3)  = (color & 2) ? 0xff : 0;
  1063.  *   *(d+4)  = *(d+5)  = (color & 4) ? 0xff : 0;
  1064.  *   *(d+6)  = *(d+7)  = (color & 8) ? 0xff : 0;
  1065.  *   *(d+8)  = *(d+9)  = (color & 16) ? 0xff : 0;
  1066.  *   *(d+10) = *(d+11) = (color & 32) ? 0xff : 0;
  1067.  *   *(d+12) = *(d+13) = (color & 64) ? 0xff : 0;
  1068.  *   *(d+14) = *(d+15) = (color & 128) ? 0xff : 0;
  1069.  */
  1070.  
  1071. static __inline__ void memset_even_8p( void *d, size_t count,
  1072.                                        u_long val1, u_long val2,
  1073.                                        u_long val3, u_long val4 )
  1074.  
  1075. {    
  1076.     __asm__ __volatile__
  1077.         ( "lsrl   #4,%1\n\t"
  1078.           "subql  #1,%1\n\t"
  1079.        "1: movel  %4,%0@+\n\t"
  1080.           "movel  %5,%0@+\n\t"
  1081.           "movel  %6,%0@+\n\t"
  1082.           "movel  %7,%0@+\n\t"
  1083.           "dbra      %1,1b\n\t"
  1084.           "subl      #65536,%1\n\t"
  1085.           "jcc      1b"
  1086.           : "=a" (d), "=d" (count)
  1087.           : "0" (d), "1" (count), "d" (val1), "d" (val2),
  1088.             "d" (val3), "d" (val4)
  1089.         );
  1090. }
  1091.  
  1092. /* Copies a 8 plane column from 's', height 'h', to 's'. */
  1093.  
  1094. static __inline__ void memmove_8p_col( void *d, void *s, u_short h,
  1095.                                        u_short bpr )
  1096.  
  1097. {    unsigned long    tmp;
  1098.  
  1099.     __asm__ __volatile__
  1100.         ( "subqw  #1,%2\n\t"
  1101.        "1: movepl %0@(0),%3\n\t"
  1102.           "movepl %3,%1@(0)\n\t"
  1103.           "movepl %0@(8),%3\n\t"
  1104.           "movepl %3,%1@(8)\n\t"
  1105.           "addaw  %7,%0\n\t"
  1106.           "addaw  %7,%1\n\t"
  1107.           "dbra   %2,1b"
  1108.           : "=a" (s), "=a" (d), "=d" (h), "=&d" (tmp)
  1109.           : "0" (s), "1" (d), "2" (h), "d" (bpr)
  1110.         );
  1111. }
  1112.  
  1113.  
  1114. /* This expands a 8 bit color into two longs for two movepl (8 plane)
  1115.  * operations.
  1116.  */
  1117.  
  1118. static __inline__ void expand8dl( unsigned char c, u_long *ret1,
  1119.                                   u_long *ret2 )
  1120.  
  1121. {    unsigned long    rv1, rv2;
  1122.     
  1123.     __asm__ __volatile__
  1124.         ( "lsrb     #1,%3\n\t"
  1125.           "scs     %0\n\t"
  1126.           "lsll     #8,%0\n\t"
  1127.           "lsrb     #1,%3\n\t"
  1128.           "scs     %0\n\t"
  1129.           "lsll     #8,%0\n\t"
  1130.           "lsrb     #1,%3\n\t"
  1131.           "scs     %0\n\t"
  1132.           "lsll     #8,%0\n\t"
  1133.           "lsrb     #1,%3\n\t"
  1134.           "scs     %0\n\t"
  1135.           "lsrb     #1,%3\n\t"
  1136.           "scs     %1\n\t"
  1137.           "lsll     #8,%1\n\t"
  1138.           "lsrb     #1,%3\n\t"
  1139.           "scs     %1\n\t"
  1140.           "lsll     #8,%1\n\t"
  1141.           "lsrb     #1,%3\n\t"
  1142.           "scs     %1\n\t"
  1143.           "lsll     #8,%1\n\t"
  1144.           "lsrb     #1,%3\n\t"
  1145.           "scs     %1"
  1146.           : "=&d" (rv1), "=&d" (rv2),"=d" (c)
  1147.           : "2" (c)
  1148.         );
  1149.  
  1150.     *ret1 = rv1;
  1151.     *ret2 = rv2;
  1152. }
  1153.  
  1154. /* This expands a 8 bit color into four longs for four movel operations
  1155.  * (8 planes).
  1156.  */
  1157.  
  1158. static __inline__ void expand8ql( unsigned char c, unsigned long *ret1,
  1159.                                   unsigned long *ret2, unsigned long
  1160.                                   *ret3, unsigned long *ret4 )
  1161.  
  1162. {    unsigned long    rv1, rv2, rv3, rv4;
  1163.     
  1164.     __asm__ __volatile__
  1165.         ( "lsrb     #1,%5\n\t"
  1166.           "scs     %0\n\t"
  1167.           "extw     %0\n\t"
  1168.           "swap     %0\n\t"
  1169.           "lsrb     #1,%5\n\t"
  1170.           "scs     %0\n\t"
  1171.           "extw     %0\n\t"
  1172.           "lsrb     #1,%5\n\t"
  1173.           "scs     %1\n\t"
  1174.           "extw     %1\n\t"
  1175.           "swap     %1\n\t"
  1176.           "lsrb     #1,%5\n\t"
  1177.           "scs   %1\n\t"
  1178.           "extw     %1\n\t"
  1179.           "lsrb     #1,%5\n\t"
  1180.           "scs     %2\n\t"
  1181.           "extw     %2\n\t"
  1182.           "swap     %2\n\t"
  1183.           "lsrb     #1,%5\n\t"
  1184.           "scs     %2\n\t"
  1185.           "extw     %2\n\t"
  1186.           "lsrb     #1,%5\n\t"
  1187.           "scs     %3\n\t"
  1188.           "extw     %3\n\t"
  1189.           "swap     %3\n\t"
  1190.           "lsrb     #1,%5\n\t"
  1191.           "scs   %3\n\t"
  1192.           "extw     %3"
  1193.           : "=&d" (rv1), "=&d" (rv2), "=&d" (rv3), "=&d" (rv4), "=d" (c)
  1194.           : "4" (c)
  1195.         );
  1196.  
  1197.     *ret1 = rv1;
  1198.     *ret2 = rv2;
  1199.     *ret3 = rv3;
  1200.     *ret4 = rv4;
  1201. }
  1202.  
  1203.  
  1204.  
  1205. /* Sets the bytes in the visible column at d, height h, to the value
  1206.  * val for a 2 plane screen. The the bis of the color in 'color' are
  1207.  * moved (8 times) to the respective bytes. This means:
  1208.  *
  1209.  * for( h times; d += bpr )
  1210.  *   *d     = (color & 1) ? 0xff : 0;
  1211.  *   *(d+2) = (color & 2) ? 0xff : 0;
  1212.  */
  1213.  
  1214. static __inline__ void memclear_2p_col( void *d, size_t h,
  1215.                                         u_short val, u_short bpr  )
  1216.  
  1217. {
  1218.     __asm__ __volatile__
  1219.         ( "subql  #1,%1\n\t"
  1220.        "1: movepw %4,%0@(0)\n\t"
  1221.           "addaw  %5,%0\n\t"
  1222.           "dbra      %1,1b"
  1223.           : "=a" (d), "=d" (h)
  1224.           : "0" (d), "1" (h), "d" (val), "r" (bpr)
  1225.         );
  1226. }
  1227.  
  1228. /* Sets a 2 plane region from 'd', length 'count' bytes, to the color
  1229.  * in val1. 'd' has to be an even address and count must be divisible
  1230.  * by 8, because only whole words and all planes are accessed. I.e.:
  1231.  *
  1232.  * for( count/4 times )
  1233.  *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
  1234.  *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
  1235.  */
  1236.  
  1237. static __inline__ void memset_even_2p( void *d, size_t count, u_long val )
  1238.  
  1239. {    
  1240.     __asm__ __volatile__
  1241.         ( "lsrl   #2,%1\n\t"
  1242.           "subql  #1,%1\n\t"
  1243.        "1: movel  %4,%0@+\n\t"
  1244.           "dbra      %1,1b\n\t"
  1245.           "subl      #65536,%1\n\t"
  1246.           "jcc      1b"
  1247.           : "=a" (d), "=d" (count)
  1248.           : "0" (d), "1" (count), "d" (val)
  1249.         );
  1250. }
  1251.  
  1252. /* Copies a 2 plane column from 's', height 'h', to 's'. */
  1253.  
  1254. static __inline__ void memmove_2p_col( void *d, void *s, u_short h,
  1255.                                        u_short bpr )
  1256.  
  1257. {    unsigned short    tmp;
  1258.  
  1259.     __asm__ __volatile__
  1260.         ( "subqw  #1,%2\n\t"
  1261.        "1: movepw %0@(0),%3\n\t"
  1262.           "movepw %3,%1@(0)\n\t"
  1263.           "addaw  %7,%0\n\t"
  1264.           "addaw  %7,%1\n\t"
  1265.           "dbra   %2,1b"
  1266.           : "=a" (s), "=a" (d), "=d" (h), "=&d" (tmp)
  1267.           : "0" (s), "1" (d), "2" (h), "d" (bpr)
  1268.         );
  1269. }
  1270.  
  1271.  
  1272. /* This expands a 2 bit color into a short for movepw (2 plane) operations. */
  1273.  
  1274. static __inline__ unsigned short expand2w( unsigned char c )
  1275.  
  1276. {    unsigned short    rv;
  1277.     
  1278.     __asm__ __volatile__
  1279.         ( "lsrb     #1,%2\n\t"
  1280.           "scs     %0\n\t"
  1281.           "lsll     #8,%0\n\t"
  1282.           "lsrb     #1,%2\n\t"
  1283.           "scs     %0\n\t"
  1284.           : "=&d" (rv), "=d" (c)
  1285.           : "1" (c)
  1286.         );
  1287.     return( rv );
  1288. }
  1289.  
  1290. /* This expands a 2 bit color into one long for a movel operation
  1291.  * (2 planes).
  1292.  */
  1293.  
  1294. static __inline__ void expand2l( unsigned char c, unsigned long *ret )
  1295.  
  1296. {    unsigned long    rv;
  1297.     
  1298.     __asm__ __volatile__
  1299.         ( "lsrb     #1,%2\n\t"
  1300.           "scs     %0\n\t"
  1301.           "extw     %0\n\t"
  1302.           "swap     %0\n\t"
  1303.           "lsrb     #1,%2\n\t"
  1304.           "scs     %0\n\t"
  1305.           "extw     %0\n\t"
  1306.           : "=&d" (rv), "=d" (c)
  1307.           : "1" (c)
  1308.         );
  1309.  
  1310.     *ret = rv;
  1311. }
  1312.  
  1313.  
  1314. /* This duplicates a byte 2 times into a short. */
  1315.  
  1316. static __inline__ unsigned short dup2w( unsigned char c )
  1317.  
  1318. {    ushort    rv;
  1319.  
  1320.     __asm__ __volatile__
  1321.         ( "moveb  %1,%0\n\t"
  1322.           "lslw   #8,%0\n\t"
  1323.           "moveb  %1,%0\n\t"
  1324.           : "=&d" (rv)
  1325.           : "d" (c)
  1326.         );
  1327.  
  1328.     return( rv );
  1329. }
  1330.  
  1331.  
  1332.  
  1333. /* ====================================================================== */
  1334.  
  1335. /* atacon_XXX routines - interface used by the world
  1336.  *
  1337.  * This system is now divided into two levels because of complications
  1338.  * caused by hardware scrolling. Top level functions:
  1339.  *
  1340.  *    atacon_bmove(), atacon_clear(), atacon_putc()
  1341.  *
  1342.  * handles y values in range [0, scr_height-1] that correspond to real
  1343.  * screen positions.
  1344.  *
  1345.  *    atacon_bmove_physical_8()   -- These functions fast implementations
  1346.  *    atacon_clear_physical_8()   -- of original atacon_XXX fns.
  1347.  *    atacon_putc_physical_8()    -- (fontwidth  != 8) may be added later
  1348.  *
  1349.  */
  1350.  
  1351.  
  1352. static int atacon_bmove (struct condata *conp,
  1353.           int sy, int sx, int dy, int dx,
  1354.           int height, int width)
  1355. {
  1356.     int unit = conp - vc_cons;
  1357.     struct display *p = &disp[unit];
  1358.     
  1359.     if ((sy <= p->cursor_y && p->cursor_y < sy+height &&
  1360.          sx <= p->cursor_x && p->cursor_x < sx+width)   ||
  1361.         (dy <= p->cursor_y && p->cursor_y < dy+height &&
  1362.          dx <= p->cursor_x && p->cursor_x < dx+width))
  1363.         atacon_cursor( conp, CM_ERASE );
  1364.     
  1365.     p->dispsw->bmove( p, sy, sx, dy, dx, height, width );
  1366.     return(0);
  1367. }
  1368.  
  1369. static int atacon_clear (struct condata *conp,
  1370.                          int sy, int sx, int height, int width)
  1371. {
  1372.     int unit = conp - vc_cons;
  1373.     register struct display *p = &disp[unit];
  1374.  
  1375.     if (sy <= p->cursor_y && p->cursor_y < sy+height &&
  1376.         sx <= p->cursor_x && p->cursor_x < sx+width)
  1377.         CURSOR_UNDRAWN();
  1378.  
  1379.     p->dispsw->clear( conp, p, sy, sx, height, width );
  1380.  
  1381.     return(0);
  1382. }
  1383.  
  1384. static int atacon_putc (struct condata *conp,
  1385.                         int c, int y, int x, int mode)
  1386. {
  1387.     int unit = conp - vc_cons;
  1388.     register struct display *p = &disp[unit];
  1389.  
  1390.     if (p->cursor_x == x && p->cursor_y == y)
  1391.         CURSOR_UNDRAWN();
  1392.     
  1393.     p->dispsw->putc( conp, p, c, y, x, mode );
  1394.  
  1395.     return(0);
  1396. }
  1397.  
  1398. static int atacon_putcs (struct condata *conp, const char *s,
  1399.                          int count, int y, int x, int mode)
  1400. {
  1401.     int unit = conp - vc_cons;
  1402.     register struct display *p = &disp[unit];
  1403.  
  1404.     if (p->cursor_y == y &&
  1405.         x <= p->cursor_x && p->cursor_x < x+count)
  1406.         CURSOR_UNDRAWN();
  1407.     
  1408.     p->dispsw->putcs( conp, p, s, count, y, x, mode );
  1409.  
  1410.     return(0);
  1411. }
  1412.  
  1413.  
  1414. static int atacon_scroll (struct condata *conp,
  1415.                           int t, int b, int dir, int count)
  1416. {
  1417.     switch (dir) {
  1418.  
  1419.       case SM_UP:
  1420.         atacon_bmove( conp, t + count, 0, t, 0,
  1421.                       (b-t-count), conp->vc_cols );
  1422.         atacon_clear( conp, b-count, 0, count, conp->vc_cols );
  1423.         break;
  1424.  
  1425.       case SM_DOWN:
  1426.         atacon_bmove( conp, t, 0, t+count, 0,
  1427.                       (b-t-count), conp->vc_cols );
  1428.  
  1429.         /* Fixed bmove() should end Arno's frustration with copying?
  1430.          * Confusius say:
  1431.          *    Man who copies in wrong direction, end up with trashed data
  1432.          */
  1433.  
  1434.         atacon_clear( conp, t, 0, count, conp->vc_cols );
  1435.         break;
  1436.  
  1437.       case SM_LEFT:
  1438.         atacon_bmove( conp, 0, t + count, 0, t,
  1439.                       conp->vc_rows, (b-t-count) );
  1440.         atacon_clear( conp, 0, b-count, conp->vc_rows, count );
  1441.         break;
  1442.  
  1443.       case SM_RIGHT:
  1444.         atacon_bmove( conp, 0, t, 0, t+count,
  1445.                       conp->vc_rows, (b-t-count) );
  1446.         atacon_clear( conp, 0, t, conp->vc_rows, count );
  1447.         break;
  1448.     }
  1449.  
  1450.     return 0;
  1451. }
  1452.  
  1453. static int atacon_switch (struct condata *conp)
  1454. {
  1455.     return 0;
  1456. }
  1457.  
  1458.  
  1459.  
  1460. /* ================================================================= */
  1461. /*                           1 Plane Functions                       */
  1462. /* ================================================================= */
  1463.  
  1464.  
  1465. static void atacon_bmove_1_plane( register struct display *p,
  1466.                                   int sy, int sx, int dy, int dx,
  1467.                                   int height, int width)
  1468. {
  1469.  
  1470.     if (sx == 0 && dx == 0 && width == p->bytes_per_row) {
  1471.         mymemmove(p->bitplane + dy * width * p->fontheight,
  1472.                   p->bitplane + sy * width * p->fontheight,
  1473.                   width * height * p->fontheight );
  1474.     } else {
  1475.         register ushort rows;
  1476.         register u_char *src;
  1477.         register u_char *dst;
  1478.         register ushort bytes      = p->bytes_per_row;
  1479.         register ushort linesize   = bytes * p->fontheight;
  1480.         
  1481.         if (dy < sy || (dy == sy && dx < sx)) {
  1482.             src  = p->bitplane + sy * linesize + sx;
  1483.             dst  = p->bitplane + dy * linesize + dx;
  1484.             for (rows = height*p->fontheight ; rows-- ;) {
  1485.                 mymemmove(dst, src, width);
  1486.                 src += bytes;
  1487.                 dst += bytes;
  1488.             }
  1489.         } else {
  1490.             src  = p->bitplane + (sy+height) * linesize + sx - bytes;
  1491.             dst  = p->bitplane + (dy+height) * linesize + dx - bytes;
  1492.  
  1493.             for (rows = height*p->fontheight ; rows-- ;) {
  1494.                 mymemmove(dst, src, width);
  1495.                 src -= bytes;
  1496.                 dst -= bytes;
  1497.             }
  1498.         }
  1499.     }
  1500. }
  1501.  
  1502.  
  1503. static void atacon_clear_1_plane( struct condata *conp, register struct
  1504.                                   display *p, int sy, int sx, int height,
  1505.                                   int width )
  1506. {
  1507.     ulong offset;
  1508.     register u_char *start;
  1509.     register ushort rows;
  1510.     register ushort bytes = p->bytes_per_row;
  1511.     register ulong size;
  1512.  
  1513.     if (sx == 0 && width == bytes) {
  1514.         offset = sy     * bytes * p->fontheight;
  1515.         size   = height * bytes * p->fontheight;
  1516.         mymemclear( p->bitplane+offset, size );
  1517.     } else {
  1518.         offset = (sy * bytes * p->fontheight) + sx;
  1519.         start = p->bitplane+offset;
  1520.         
  1521.         for (rows = height*p->fontheight; rows-- ; start += bytes)
  1522.             mymemclear_small(start, width);
  1523.     }
  1524. }
  1525.  
  1526.  
  1527. static void atacon_putc_1_plane( struct condata *conp, struct display *p,
  1528.                                  int c, int y, int x, int mode)
  1529. {
  1530.     register u_char   *dest;
  1531.     register u_char   *cdat;
  1532.     register ushort   rows;
  1533.     u_short           bytes;
  1534.     ulong             offset;
  1535.  
  1536.     if (!FONT_CNV(c)) return;
  1537.  
  1538.     bytes  = p->bytes_per_row;
  1539.     offset = y * p->fontheight * bytes + x;
  1540.     dest  = p->bitplane + offset;
  1541.     cdat  = p->fontdata + (c * p->fontheight);
  1542.  
  1543.     if (conp->vc_intensity != 1 || conp->vc_reverse ^ conp->vc_decscnm) {
  1544.         register u_char    andmask, xormask, c;
  1545.         register int    bold;
  1546.         
  1547.         andmask = (conp->vc_intensity == 0) ? 0x55 : 0xff;
  1548.         xormask = (conp->vc_reverse ^ conp->vc_decscnm) ? 0xff : 0;
  1549.         bold = (conp->vc_intensity == 2);
  1550.         
  1551.         for (rows = p->fontheight ; rows-- ; dest += bytes) {
  1552.             c = *cdat++;
  1553.             if (rows == 0 && conp->vc_underline) c = 0xff;
  1554.             c = (c & andmask) ^ xormask;
  1555.             if (bold) c |= c >> 1;
  1556.             *dest = c;
  1557.         }
  1558.     }
  1559.     else {
  1560.         
  1561.         for (rows = p->fontheight ; rows-- ; dest += bytes)
  1562.             *dest = *cdat++;
  1563.  
  1564.         if (conp->vc_underline)
  1565.             dest[-bytes] ^= ~0;
  1566.     }
  1567. }
  1568.  
  1569.  
  1570. static void atacon_putcs_1_plane( struct condata *conp, struct
  1571.                                   display *p, const char *s,
  1572.                                   int count, int y, int x, int mode)
  1573. {
  1574.     register u_char   *dest, *cdat;
  1575.     register ushort   rows, bytes;
  1576.     register u_char   c;
  1577.     u_char   *dest0;
  1578.     ulong    offset;
  1579.     int         effects = (conp->vc_underline || conp->vc_intensity != 1 ||
  1580.                         (conp->vc_reverse ^ conp->vc_decscnm));
  1581.     
  1582.     if (!count) return;
  1583.     
  1584.     bytes  = p->bytes_per_row;
  1585.     offset = y * p->fontheight * bytes + x;
  1586.     dest0  = p->bitplane + offset;
  1587.  
  1588. #if defined (__GNUC__) && defined (__mc68000__)
  1589.     if (!effects && p->fontheight == 8) {
  1590.         void *tmpa;
  1591.         /* Ultra special support for 8x8 fonts, as its nice and easy
  1592.          * and the console driver seems to spend most of its time in
  1593.          * here. Would take another 4 instructions to support,
  1594.          * (fontheight != 8) but I have an inbuilt suspicion of mulu's.
  1595.          * A hangover from my 68000 days, I guess.
  1596.          *
  1597.          * Both code and register use mirrors the C code directly below:
  1598.          *
  1599.          * a0 -- dest & dest0  [uses stack] 
  1600.          * a1 -- cdat     ; a2 -- s      ; a3 -- fontdata
  1601.          * d0 -- scratch  ; d1 -- count  ; d2 -- bytes
  1602.          * 
  1603.          */
  1604.         __asm__ __volatile__
  1605.                ("subqw  #1,%1\n\t"
  1606.                 "moveq  #0,d0\n\t"
  1607.              "1: moveb  %2@+,d0\n\t"
  1608. #ifndef WHOLE_FONT
  1609.                 "cmpb   #32,d0  ; jlt 2f ; cmpb #127,d0 ; jge 2f\n\t"
  1610.                 "subb   #32,d0  ; jra 3f\n\t"
  1611.              "2: cmpb   #160,d0 ; jlt 1b ; cmpb #255,d0 ; jeq 1b\n\t"
  1612.                 "subb   #64,d0\n\t3: "
  1613. #else
  1614.                 "moveb %9@(d0:w),d0 ; beq 1b\n\t"
  1615. #endif
  1616.                "lea %7@(d0:w:8),%3 ; movel %0,sp@-\n\t"
  1617.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 0 */
  1618.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 1 */
  1619.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 2 */
  1620.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 3 */
  1621.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 4 */
  1622.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 5 */
  1623.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 6 */
  1624.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 7 */
  1625.                 "movel  sp@+,%0 ; addql #1,%0 ; dbra %1,1b\n\t"
  1626.                 : "=a" (dest0), "=d" (count), "=a" (s), "=&a" (tmpa)
  1627.                 : "0" (dest0), "1" (count), "2" (s), "a" (p->fontdata),
  1628.                   "d" (bytes)
  1629. #ifdef WHOLE_FONT
  1630.                   , "a" (conp->vc_translate)
  1631. #endif
  1632.                 : "d0" /* Sorry, it isn't possible to let gcc choose
  1633.                         * this register, too, because this would
  1634.                         * require another output operand and thus give
  1635.                         * more than 10 parameters total. But gcc can
  1636.                         * only handle up to 10 parameters at present :-(
  1637.                         */
  1638.                );
  1639.         return;
  1640.     }
  1641.     if (!effects && p->fontheight == 16) {
  1642.         /* ++roman: the same for 8x16 */
  1643.         void *tmpa;
  1644.         __asm__ __volatile__
  1645.                ("subqw  #1,%1\n\t"
  1646.              "1: moveq  #0,d0   ; moveb %2@+,d0\n\t"
  1647. #ifndef WHOLE_FONT
  1648.                 "cmpb   #32,d0  ; jlt 2f ; cmpb #127,d0 ; jge 2f\n\t"
  1649.                 "subb   #32,d0  ; jra 3f\n\t"
  1650.              "2: cmpb   #160,d0 ; jlt 1b ; cmpb #255,d0 ; jeq 1b\n\t"
  1651.                 "subb   #64,d0\n\t3: "
  1652. #else
  1653.                 "moveb %9@(d0:w),d0 ; beq 1b\n\t"
  1654. #endif
  1655.                "lslw #4,d0     ; lea %7@(d0:w),%3 ; movel %0,sp@-\n\t"
  1656.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 0 */
  1657.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 1 */
  1658.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 2 */
  1659.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 3 */
  1660.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 4 */
  1661.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 5 */
  1662.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 6 */
  1663.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 7 */
  1664.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 8 */
  1665.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 9 */
  1666.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 10 */
  1667.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 11 */
  1668.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 12 */
  1669.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 13 */
  1670.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 14 */
  1671.                " moveb  %3@+,%0@; addaw %8,%0\n\t" /* 15 */
  1672.                 "movel  sp@+,%0 ; addql #1,%0 ; dbra %1,1b\n\t"
  1673.                 : "=a" (dest0), "=d" (count), "=a" (s), "=&a" (tmpa)
  1674.                 : "0" (dest0), "1" (count), "2" (s), "a" (p->fontdata),
  1675.                   "d" (bytes)
  1676. #ifdef WHOLE_FONT
  1677.                   , "a" (conp->vc_translate)
  1678. #endif
  1679.                 : "d0" /* Sorry, it isn't possible to let gcc choose
  1680.                         * this register, too, because this would
  1681.                         * require another output operand and thus give
  1682.                         * more than 10 parameters total. But gcc can
  1683.                         * only handle up to 10 parameters at present :-(
  1684.                         */
  1685.                );
  1686.         return;
  1687.     }
  1688. #endif
  1689.  
  1690.     if (effects) {
  1691.         register u_char    andmask, xormask, ch;
  1692.         register int    bold;
  1693.         
  1694.         andmask = (conp->vc_intensity == 0) ? 0x55 : 0xff;
  1695.         xormask = (conp->vc_reverse ^ conp->vc_decscnm) ? 0xff : 0;
  1696.         bold = (conp->vc_intensity == 2);
  1697.  
  1698.         while (count--) {
  1699.             c = *(s++);
  1700.             if (!FONT_CNV(c)) continue;
  1701.  
  1702.             dest = dest0++;
  1703.             cdat  = p->fontdata + (c * p->fontheight);
  1704.  
  1705.             for (rows = p->fontheight ; rows-- ; dest += bytes) {
  1706.                 ch = *cdat++;
  1707.                 if (rows == 0 && conp->vc_underline) ch = 0xff;
  1708.                 ch = (ch & andmask) ^ xormask;
  1709.                 if (bold) ch |= ch >> 1;
  1710.                 *dest = ch;
  1711.             }
  1712.         }
  1713.     }
  1714.     else {
  1715.  
  1716.         while (count--) {
  1717.             c = *(s++);
  1718.             if (!FONT_CNV(c)) continue;
  1719.  
  1720.             dest = dest0++;
  1721.             cdat  = p->fontdata + (c * p->fontheight);
  1722.  
  1723.             for (rows = p->fontheight ; rows-- ; dest += bytes)
  1724.                 *dest = *cdat++;
  1725.         }
  1726.     }
  1727. }
  1728.  
  1729.  
  1730. static void atacon_rev_char_1_plane( struct display *display, int x, int y )
  1731.  
  1732. {    u_char    *p;
  1733.     int        offs;
  1734.     u_short j;
  1735.     
  1736.     offs = y * display->fontheight * display->bytes_per_row + x;
  1737.  
  1738.     p = display->bitplane + offs;
  1739.     j = display->fontheight - 1;
  1740.     __asm__ __volatile__
  1741.         ("1: notb  %0@ ; addaw %4,%0\n\t"
  1742.          "dbra  %1,1b"
  1743.          : "=a" (p), "=d" (j)
  1744.          : "0" (p), "1" (j),
  1745.          "d" (display->bytes_per_row)
  1746.          );
  1747. }
  1748.  
  1749.  
  1750.  
  1751. #ifdef CONFIG_ATARI_2PLANE
  1752.  
  1753. /* ================================================================= */
  1754. /*                           2 Plane Functions                       */
  1755. /* ================================================================= */
  1756.  
  1757.  
  1758. /* Increment/decrement 2 plane addresses */
  1759.  
  1760. #define    INC_2P(p)    do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0)
  1761. #define    DEC_2P(p)    do { if ((long)(--(p)) & 1) (p) -= 2; } while(0)
  1762.  
  1763. /* Convert a standard 4 bit color to our 2 bit color assignment:
  1764.  * If at least two RGB channels are active, the low bit is turned on;
  1765.  * The intensity bit (b3) is shifted into b1.
  1766.  */
  1767.  
  1768. #define    COLOR_2P(c)    (((c & 7) >= 3 && (c & 7) != 4) | (c & 8) >> 2)
  1769.  
  1770.  
  1771. static void atacon_bmove_2_plane( register struct display *p,
  1772.                                   int sy, int sx, int dy, int dx,
  1773.                                   int height, int width)
  1774. {
  1775.     /* bmove() has to distinguish two major cases: If both, source and
  1776.      * destination, start at even addresses or both are at odd
  1777.      * addresses, just the first odd and last even column (if present)
  1778.      * require special treatment (memmove_col()). The rest between
  1779.      * then can be copied by normal operations, because all adjancent
  1780.      * bytes are affected and are to be stored in the same order.
  1781.      *   The pathological case is when the move should go from an odd
  1782.      * address to an even or vice versa. Since the bytes in the plane
  1783.      * words must be assembled in new order, it seems wisest to make
  1784.      * all movements by memmove_col().
  1785.      */
  1786.  
  1787.     if (sx == 0 && dx == 0 && width == p->bytes_per_row/2) {
  1788.         /* Special (but often used) case: Moving whole lines can be
  1789.          * done with memmove()
  1790.          */
  1791.         mymemmove( p->bitplane + dy * p->bytes_per_row * p->fontheight,
  1792.                    p->bitplane + sy * p->bytes_per_row * p->fontheight,
  1793.                    p->bytes_per_row * height * p->fontheight );
  1794.     } else {
  1795.         register ushort rows, cols;
  1796.         register u_char *src;
  1797.         register u_char *dst;
  1798.         register ushort bytes    = p->bytes_per_row;
  1799.         register ushort linesize = bytes * p->fontheight;
  1800.                unsigned colsize  = height * p->fontheight;
  1801.                unsigned upwards  = (dy < sy) || (dy == sy && dx < sx);
  1802.  
  1803.         if ((sx & 1) == (dx & 1)) {
  1804.             /* odd->odd or even->even */
  1805.  
  1806.             if (upwards) {
  1807.  
  1808.                 src = p->bitplane + sy * linesize + (sx>>1)*4 + (sx & 1);
  1809.                 dst = p->bitplane + dy * linesize + (dx>>1)*4 + (dx & 1);
  1810.  
  1811.                 if (sx & 1) {
  1812.                     memmove_2p_col( dst, src, colsize, bytes );
  1813.                     src += 3;
  1814.                     dst += 3;
  1815.                     --width;
  1816.                 }
  1817.  
  1818.                 if (width > 1) {
  1819.                     for( rows = colsize; rows > 0; --rows ) {
  1820.                         mymemmove( dst, src, (width>>1)*4 );
  1821.                         src += bytes;
  1822.                         dst += bytes;
  1823.                     }
  1824.                 }
  1825.                 
  1826.                 if (width & 1) {
  1827.                     src -= colsize * bytes;
  1828.                     dst -= colsize * bytes;
  1829.                     memmove_2p_col( dst + (width>>1)*4, src + (width>>1)*4,
  1830.                                     colsize, bytes );
  1831.                 }
  1832.             }
  1833.             else {
  1834.  
  1835.                 if (!((sx+width-1) & 1)) {
  1836.                     src = p->bitplane + sy * linesize + ((sx+width-1)>>1)*4;
  1837.                     dst = p->bitplane + dy * linesize + ((dx+width-1)>>1)*4;
  1838.                     memmove_2p_col( dst, src, colsize, bytes );
  1839.                     --width;
  1840.                 }
  1841.  
  1842.                 src = p->bitplane + sy * linesize + (sx>>1)*4 + (sx & 1);
  1843.                 dst = p->bitplane + dy * linesize + (dx>>1)*4 + (dx & 1);
  1844.  
  1845.                 if (width > 1) {
  1846.                     src += colsize * bytes + (sx & 1)*3;
  1847.                     dst += colsize * bytes + (sx & 1)*3;
  1848.                     for( rows = colsize; rows > 0; --rows ) {
  1849.                         src -= bytes;
  1850.                         dst -= bytes;
  1851.                         mymemmove( dst, src, (width>>1)*4 );
  1852.                     }
  1853.                 }
  1854.  
  1855.                 if (width & 1) {
  1856.                     memmove_2p_col( dst-3, src-3, colsize, bytes );
  1857.                 }
  1858.  
  1859.             }
  1860.         }
  1861.         else {
  1862.             /* odd->even or even->odd */
  1863.  
  1864.             if (upwards) {
  1865.                 src = p->bitplane + sy * linesize + (sx>>1)*4 + (sx & 1);
  1866.                 dst = p->bitplane + dy * linesize + (dx>>1)*4 + (dx & 1);
  1867.                 for( cols = width; cols > 0; --cols ) {
  1868.                     memmove_2p_col( dst, src, colsize, bytes );
  1869.                     INC_2P( src );
  1870.                     INC_2P( dst );
  1871.                 }
  1872.             }
  1873.             else {
  1874.                 sx += width-1;
  1875.                 dx += width-1;
  1876.                 src = p->bitplane + sy * linesize + (sx>>1)*4 + (sx & 1);
  1877.                 dst = p->bitplane + dy * linesize + (dx>>1)*4 + (dx & 1);
  1878.                 for( cols = width; cols > 0; --cols ) {
  1879.                     memmove_2p_col( dst, src, colsize, bytes );
  1880.                     DEC_2P( src );
  1881.                     DEC_2P( dst );
  1882.                 }
  1883.             }
  1884.         }
  1885.             
  1886.         
  1887.     }
  1888. }
  1889.  
  1890.  
  1891. static void atacon_clear_2_plane( struct condata *conp, register struct
  1892.                                   display *p, int sy, int sx, int height,
  1893.                                   int width )
  1894. {
  1895.     ulong offset;
  1896.     register u_char *start;
  1897.     register ushort rows;
  1898.     register ushort bytes = p->bytes_per_row;
  1899.     ushort          lines = height * p->fontheight;
  1900.     register ulong  size;
  1901.     u_long          cval;
  1902.     u_short            pcval;
  1903.     
  1904.     expand2l( COLOR_2P(conp->vc_video_erase_char >> 12), &cval );
  1905.     
  1906.     if (sx == 0 && width == bytes/2) {
  1907.  
  1908.         offset = sy * bytes * p->fontheight;
  1909.         size   = lines * bytes;
  1910.         memset_even_2p( p->bitplane+offset, size, cval );
  1911.  
  1912.     } else {
  1913.  
  1914.         offset = (sy * bytes * p->fontheight) + (sx>>1)*4 + (sx & 1);
  1915.         start = p->bitplane + offset;
  1916.         pcval = expand2w( COLOR_2P(conp->vc_video_erase_char >> 12) );
  1917.         
  1918.         /* Clears are split if the region starts at an odd column or
  1919.          * end at an even column. These extra columns are spread
  1920.          * across the interleaved planes. All in between can be
  1921.          * cleared by normal mymemclear_small(), because both bytes of
  1922.          * the single plane words are affected.
  1923.          */
  1924.  
  1925.         if (sx & 1) {
  1926.             memclear_2p_col( start, lines, pcval, bytes );
  1927.             start += 3;
  1928.             width--;
  1929.         }
  1930.  
  1931.         if (width & 1) {
  1932.             memclear_2p_col( start + (width>>1)*4, lines, pcval, bytes );
  1933.             width--;
  1934.         }
  1935.  
  1936.         if (width) {
  1937.             for( rows = lines; rows-- ; start += bytes )
  1938.                 memset_even_2p( start, width*2, cval );
  1939.         }
  1940.     }
  1941. }
  1942.  
  1943.  
  1944. static void atacon_putc_2_plane( struct condata *conp, struct display *p,
  1945.                                  int c, int y, int x, int mode)
  1946.  
  1947. {    register u_char   *dest;
  1948.     register u_char   *cdat;
  1949.     register ushort   rows;
  1950.     register u_short  bytes = p->bytes_per_row;
  1951.     ulong              eorx, fgx, bgx, fdx;
  1952.  
  1953.     if (!FONT_CNV(c)) return;
  1954.  
  1955.     dest  = p->bitplane + y * p->fontheight * bytes + (x>>1)*4 + (x & 1);
  1956.     cdat  = p->fontdata + (c * p->fontheight);
  1957.  
  1958.     fgx   = expand2w( COLOR_2P(conp->vc_attr) );
  1959.     bgx   = expand2w( COLOR_2P(conp->vc_attr >> 4) );
  1960.     eorx  = fgx ^ bgx;
  1961.         
  1962.     for( rows = p->fontheight ; rows-- ; dest += bytes ) {
  1963.         fdx = dup2w( *cdat++ );
  1964.         __asm__ __volatile__ ( "movepw %1,%0@(0)" : /* no outputs */
  1965.                                : "a" (dest), "d" ((fdx & eorx) ^ bgx) );
  1966.     }
  1967.  
  1968.     if (conp->vc_underline) {
  1969.         __asm__ __volatile__ ( "movepw %1,%0@(0)" : /* no outputs */
  1970.                                : "a" (dest-bytes), "d" (fgx) );
  1971.     }
  1972. }
  1973.  
  1974.  
  1975. static void atacon_putcs_2_plane( struct condata *conp, struct
  1976.                                   display *p, const char *s,
  1977.                                   int count, int y, int x, int mode)
  1978.  
  1979. {    register u_char   *dest, *dest0;
  1980.     register u_char   *cdat, c;
  1981.     register ushort   rows;
  1982.     register u_short  bytes;
  1983.     ulong              eorx, fgx, bgx, fdx;
  1984.  
  1985.     bytes = p->bytes_per_row;
  1986.     dest0 = p->bitplane + y * p->fontheight * bytes + (x>>1)*4 + (x & 1);
  1987.     fgx   = expand2w( COLOR_2P(conp->vc_attr) );
  1988.     bgx   = expand2w( COLOR_2P(conp->vc_attr >> 4) );
  1989.     eorx  = fgx ^ bgx;
  1990.  
  1991.     while( count-- > 0 ) {
  1992.  
  1993.         c = *s++;
  1994.         if (!FONT_CNV(c)) continue;
  1995.         cdat  = p->fontdata + (c * p->fontheight);
  1996.     
  1997.         for( rows = p->fontheight, dest = dest0; rows-- ; dest += bytes ) {
  1998.             fdx = dup2w( *cdat++ );
  1999.             __asm__ __volatile__ ( "movepw %1,%0@(0)" : /* no outputs */
  2000.                                    : "a" (dest), "d" ((fdx & eorx) ^ bgx) );
  2001.         }
  2002.  
  2003.         if (conp->vc_underline) {
  2004.             __asm__ __volatile__ ( "movepw %1,%0@(0)" : /* no outputs */
  2005.                                    : "a" (dest-bytes), "d" (fgx) );
  2006.         }
  2007.  
  2008.         INC_2P(dest0);
  2009.     }
  2010. }
  2011.  
  2012.  
  2013. static void atacon_rev_char_2_plane( struct display *display, int x, int y )
  2014.  
  2015. {    u_char    *p;
  2016.     u_short j;
  2017.     
  2018.     p = display->bitplane +
  2019.         y * display->fontheight * display->bytes_per_row +
  2020.         (x>>1)*4 + (x & 1);
  2021.     j = display->fontheight - 1;
  2022.  
  2023.     __asm__ __volatile__
  2024.         /* This should really obey the individual character's
  2025.          * background and foreground colors instead of simply
  2026.          * inverting.
  2027.          */
  2028.         ("1: notb  %0@ ; notb %0@(2)\n\t"
  2029.          "addaw %4,%0\n\t"
  2030.          "dbra  %1,1b"
  2031.          : "=a" (p), "=d" (j)
  2032.          : "0" (p), "1" (j), "d" (display->bytes_per_row)
  2033.          );
  2034. }
  2035.  
  2036.  
  2037. #endif /* CONFIG_ATARI_2PLANE */
  2038.  
  2039.  
  2040.  
  2041. #ifdef CONFIG_ATARI_4PLANE
  2042.  
  2043. /* ================================================================= */
  2044. /*                           4 Plane Functions                       */
  2045. /* ================================================================= */
  2046.  
  2047.  
  2048. /* Increment/decrement 4 plane addresses */
  2049.  
  2050. #define    INC_4P(p)    do { if (!((long)(++(p)) & 1)) (p) += 6; } while(0)
  2051. #define    DEC_4P(p)    do { if ((long)(--(p)) & 1) (p) -= 6; } while(0)
  2052.  
  2053.  
  2054. static void atacon_bmove_4_plane( register struct display *p,
  2055.                                   int sy, int sx, int dy, int dx,
  2056.                                   int height, int width)
  2057. {
  2058.     /* bmove() has to distinguish two major cases: If both, source and
  2059.      * destination, start at even addresses or both are at odd
  2060.      * addresses, just the first odd and last even column (if present)
  2061.      * require special treatment (memmove_col()). The rest between
  2062.      * then can be copied by normal operations, because all adjancent
  2063.      * bytes are affected and are to be stored in the same order.
  2064.      *   The pathological case is when the move should go from an odd
  2065.      * address to an even or vice versa. Since the bytes in the plane
  2066.      * words must be assembled in new order, it seems wisest to make
  2067.      * all movements by memmove_col().
  2068.      */
  2069.  
  2070.     if (sx == 0 && dx == 0 && width == p->bytes_per_row/4) {
  2071.         /* Special (but often used) case: Moving whole lines can be
  2072.          * done with memmove()
  2073.          */
  2074.         mymemmove( p->bitplane + dy * p->bytes_per_row * p->fontheight,
  2075.                    p->bitplane + sy * p->bytes_per_row * p->fontheight,
  2076.                    p->bytes_per_row * height * p->fontheight );
  2077.     } else {
  2078.         register ushort rows, cols;
  2079.         register u_char *src;
  2080.         register u_char *dst;
  2081.         register ushort bytes    = p->bytes_per_row;
  2082.         register ushort linesize = bytes * p->fontheight;
  2083.                unsigned colsize  = height * p->fontheight;
  2084.                unsigned upwards  = (dy < sy) || (dy == sy && dx < sx);
  2085.  
  2086.         if ((sx & 1) == (dx & 1)) {
  2087.             /* odd->odd or even->even */
  2088.  
  2089.             if (upwards) {
  2090.  
  2091.                 src = p->bitplane + sy * linesize + (sx>>1)*8 + (sx & 1);
  2092.                 dst = p->bitplane + dy * linesize + (dx>>1)*8 + (dx & 1);
  2093.  
  2094.                 if (sx & 1) {
  2095.                     memmove_4p_col( dst, src, colsize, bytes );
  2096.                     src += 7;
  2097.                     dst += 7;
  2098.                     --width;
  2099.                 }
  2100.  
  2101.                 if (width > 1) {
  2102.                     for( rows = colsize; rows > 0; --rows ) {
  2103.                         mymemmove( dst, src, (width>>1)*8 );
  2104.                         src += bytes;
  2105.                         dst += bytes;
  2106.                     }
  2107.                 }
  2108.                 
  2109.                 if (width & 1) {
  2110.                     src -= colsize * bytes;
  2111.                     dst -= colsize * bytes;
  2112.                     memmove_4p_col( dst + (width>>1)*8, src + (width>>1)*8,
  2113.                                     colsize, bytes );
  2114.                 }
  2115.             }
  2116.             else {
  2117.  
  2118.                 if (!((sx+width-1) & 1)) {
  2119.                     src = p->bitplane + sy * linesize + ((sx+width-1)>>1)*8;
  2120.                     dst = p->bitplane + dy * linesize + ((dx+width-1)>>1)*8;
  2121.                     memmove_4p_col( dst, src, colsize, bytes );
  2122.                     --width;
  2123.                 }
  2124.  
  2125.                 src = p->bitplane + sy * linesize + (sx>>1)*8 + (sx & 1);
  2126.                 dst = p->bitplane + dy * linesize + (dx>>1)*8 + (dx & 1);
  2127.  
  2128.                 if (width > 1) {
  2129.                     src += colsize * bytes + (sx & 1)*7;
  2130.                     dst += colsize * bytes + (sx & 1)*7;
  2131.                     for( rows = colsize; rows > 0; --rows ) {
  2132.                         src -= bytes;
  2133.                         dst -= bytes;
  2134.                         mymemmove( dst, src, (width>>1)*8 );
  2135.                     }
  2136.                 }
  2137.  
  2138.                 if (width & 1) {
  2139.                     memmove_4p_col( dst-7, src-7, colsize, bytes );
  2140.                 }
  2141.  
  2142.             }
  2143.         }
  2144.         else {
  2145.             /* odd->even or even->odd */
  2146.  
  2147.             if (upwards) {
  2148.                 src = p->bitplane + sy * linesize + (sx>>1)*8 + (sx & 1);
  2149.                 dst = p->bitplane + dy * linesize + (dx>>1)*8 + (dx & 1);
  2150.                 for( cols = width; cols > 0; --cols ) {
  2151.                     memmove_4p_col( dst, src, colsize, bytes );
  2152.                     INC_4P( src );
  2153.                     INC_4P( dst );
  2154.                 }
  2155.             }
  2156.             else {
  2157.                 sx += width-1;
  2158.                 dx += width-1;
  2159.                 src = p->bitplane + sy * linesize + (sx>>1)*8 + (sx & 1);
  2160.                 dst = p->bitplane + dy * linesize + (dx>>1)*8 + (dx & 1);
  2161.                 for( cols = width; cols > 0; --cols ) {
  2162.                     memmove_4p_col( dst, src, colsize, bytes );
  2163.                     DEC_4P( src );
  2164.                     DEC_4P( dst );
  2165.                 }
  2166.             }
  2167.         }
  2168.             
  2169.         
  2170.     }
  2171. }
  2172.  
  2173.  
  2174. static void atacon_clear_4_plane( struct condata *conp, register struct
  2175.                                   display *p, int sy, int sx, int height,
  2176.                                   int width )
  2177. {
  2178.     ulong offset;
  2179.     register u_char *start;
  2180.     register ushort rows;
  2181.     register ushort bytes = p->bytes_per_row;
  2182.     ushort          lines = height * p->fontheight;
  2183.     register ulong  size;
  2184.     u_long          cval1, cval2, pcval;
  2185.  
  2186.     expand4dl( conp->vc_video_erase_char >> 12, &cval1, &cval2 );
  2187.     
  2188.     if (sx == 0 && width == bytes/4) {
  2189.  
  2190.         offset = sy * bytes * p->fontheight;
  2191.         size   = lines * bytes;
  2192.         memset_even_4p( p->bitplane+offset, size, cval1, cval2 );
  2193.  
  2194.     } else {
  2195.  
  2196.         offset = (sy * bytes * p->fontheight) + (sx>>1)*8 + (sx & 1);
  2197.         start = p->bitplane + offset;
  2198.         pcval = expand4l( conp->vc_video_erase_char >> 12 );
  2199.         
  2200.         /* Clears are split if the region starts at an odd column or
  2201.          * end at an even column. These extra columns are spread
  2202.          * across the interleaved planes. All in between can be
  2203.          * cleared by normal mymemclear_small(), because both bytes of
  2204.          * the single plane words are affected.
  2205.          */
  2206.  
  2207.         if (sx & 1) {
  2208.             memclear_4p_col( start, lines, pcval, bytes );
  2209.             start += 7;
  2210.             width--;
  2211.         }
  2212.  
  2213.         if (width & 1) {
  2214.             memclear_4p_col( start + (width>>1)*8, lines, pcval, bytes );
  2215.             width--;
  2216.         }
  2217.  
  2218.         if (width) {
  2219.             for( rows = lines; rows-- ; start += bytes )
  2220.                 memset_even_4p( start, width*4, cval1, cval2 );
  2221.         }
  2222.     }
  2223. }
  2224.  
  2225.  
  2226. static void atacon_putc_4_plane( struct condata *conp, struct display *p,
  2227.                                  int c, int y, int x, int mode)
  2228. {    register u_char   *dest;
  2229.     register u_char   *cdat;
  2230.     register ushort   rows;
  2231.     register u_short  bytes = p->bytes_per_row;
  2232.     ulong              eorx, fgx, bgx, fdx;
  2233.  
  2234.     if (!FONT_CNV(c)) return;
  2235.  
  2236.     dest  = p->bitplane + y * p->fontheight * bytes + (x>>1)*8 + (x & 1);
  2237.     cdat  = p->fontdata + (c * p->fontheight);
  2238.  
  2239.     fgx   = expand4l( conp->vc_attr );
  2240.     bgx   = expand4l( conp->vc_attr >> 4 );
  2241.     eorx  = fgx ^ bgx;
  2242.         
  2243.     for( rows = p->fontheight ; rows-- ; dest += bytes ) {
  2244.         fdx = dup4l( *cdat++ );
  2245.         __asm__ __volatile__ ( "movepl %1,%0@(0)" : /* no outputs */
  2246.                                : "a" (dest), "d" ((fdx & eorx) ^ bgx) );
  2247.     }
  2248.  
  2249.     if (conp->vc_underline) {
  2250.         __asm__ __volatile__ ( "movepl %1,%0@(0)" : /* no outputs */
  2251.                                : "a" (dest-bytes), "d" (fgx) );
  2252.     }
  2253. }
  2254.  
  2255.  
  2256. static void atacon_putcs_4_plane( struct condata *conp, struct
  2257.                                   display *p, const char *s,
  2258.                                   int count, int y, int x, int mode)
  2259. {    register u_char   *dest, *dest0;
  2260.     register u_char   *cdat, c;
  2261.     register ushort   rows;
  2262.     register u_short  bytes;
  2263.     ulong              eorx, fgx, bgx, fdx;
  2264.  
  2265.     bytes = p->bytes_per_row;
  2266.     dest0 = p->bitplane + y * p->fontheight * bytes + (x>>1)*8 + (x & 1);
  2267.     fgx   = expand4l( conp->vc_attr );
  2268.     bgx   = expand4l( conp->vc_attr >> 4 );
  2269.     eorx  = fgx ^ bgx;
  2270.  
  2271.     while( count-- > 0 ) {
  2272.  
  2273.         /* I think, unrolling the loops like in the 1 plane case isn't
  2274.          * practicable here, because the body is much longer for 4
  2275.          * planes (mostly the dup4l()). I guess, unrolling this would
  2276.          * need more than 256 bytes and so exceed the instruction
  2277.          * cache :-(
  2278.          */
  2279.         
  2280.         c = *s++;
  2281.         if (!FONT_CNV(c)) continue;
  2282.         cdat  = p->fontdata + (c * p->fontheight);
  2283.     
  2284.         for( rows = p->fontheight, dest = dest0; rows-- ; dest += bytes ) {
  2285.             fdx = dup4l( *cdat++ );
  2286.             __asm__ __volatile__ ( "movepl %1,%0@(0)" : /* no outputs */
  2287.                                    : "a" (dest), "d" ((fdx & eorx) ^ bgx) );
  2288.         }
  2289.  
  2290.         if (conp->vc_underline) {
  2291.             __asm__ __volatile__ ( "movepl %1,%0@(0)" : /* no outputs */
  2292.                                    : "a" (dest-bytes), "d" (fgx) );
  2293.         }
  2294.  
  2295.         INC_4P(dest0);
  2296.     }
  2297. }
  2298.  
  2299.  
  2300. static void atacon_rev_char_4_plane( struct display *display, int x, int y )
  2301.  
  2302. {    u_char    *p;
  2303.     u_short j;
  2304.     
  2305.     p = display->bitplane +
  2306.         y * display->fontheight * display->bytes_per_row +
  2307.         (x>>1)*8 + (x & 1);
  2308.     j = display->fontheight - 1;
  2309.  
  2310.     __asm__ __volatile__
  2311.         /* This should really obey the individual character's
  2312.          * background and foreground colors instead of simply
  2313.          * inverting.
  2314.          */
  2315.         ("1: notb  %0@ ; notb %0@(2) ; notb %0@(4) ; notb %0@(6)\n\t"
  2316.          "addaw %4,%0\n\t"
  2317.          "dbra  %1,1b"
  2318.          : "=a" (p), "=d" (j)
  2319.          : "0" (p), "1" (j), "d" (display->bytes_per_row)
  2320.          );
  2321. }
  2322.  
  2323.  
  2324. #endif /* CONFIG_ATARI_4PLANE */
  2325.  
  2326.  
  2327.  
  2328. #ifdef CONFIG_ATARI_8PLANE
  2329.  
  2330. /* ================================================================= */
  2331. /*                           8 Plane Functions                       */
  2332. /* ================================================================= */
  2333.  
  2334.  
  2335. /* In 8 plane mode, 256 colors would be possible, but only the first
  2336.  * 16 are used by the console code (the upper 4 bits are
  2337.  * background/unused). For that, the following functions mask off the
  2338.  * higher 4 bits of each color.
  2339.  */
  2340.  
  2341. /* Increment/decrement 8 plane addresses */
  2342.  
  2343. #define    INC_8P(p)    do { if (!((long)(++(p)) & 1)) (p) += 14; } while(0)
  2344. #define    DEC_8P(p)    do { if ((long)(--(p)) & 1) (p) -= 14; } while(0)
  2345.  
  2346.  
  2347. static void atacon_bmove_8_plane( register struct display *p,
  2348.                                   int sy, int sx, int dy, int dx,
  2349.                                   int height, int width)
  2350. {
  2351.     /* bmove() has to distinguish two major cases: If both, source and
  2352.      * destination, start at even addresses or both are at odd
  2353.      * addresses, just the first odd and last even column (if present)
  2354.      * require special treatment (memmove_col()). The rest between
  2355.      * then can be copied by normal operations, because all adjancent
  2356.      * bytes are affected and are to be stored in the same order.
  2357.      *   The pathological case is when the move should go from an odd
  2358.      * address to an even or vice versa. Since the bytes in the plane
  2359.      * words must be assembled in new order, it seems wisest to make
  2360.      * all movements by memmove_col().
  2361.      */
  2362.  
  2363.     if (sx == 0 && dx == 0 && width == p->bytes_per_row/8) {
  2364.         /* Special (but often used) case: Moving whole lines can be
  2365.          * done with memmove()
  2366.          */
  2367.         mymemmove( p->bitplane + dy * p->bytes_per_row * p->fontheight,
  2368.                    p->bitplane + sy * p->bytes_per_row * p->fontheight,
  2369.                    p->bytes_per_row * height * p->fontheight );
  2370.     } else {
  2371.         register ushort rows, cols;
  2372.         register u_char *src;
  2373.         register u_char *dst;
  2374.         register ushort bytes    = p->bytes_per_row;
  2375.         register ushort linesize = bytes * p->fontheight;
  2376.                unsigned colsize  = height * p->fontheight;
  2377.                unsigned upwards  = (dy < sy) || (dy == sy && dx < sx);
  2378.  
  2379.         if ((sx & 1) == (dx & 1)) {
  2380.             /* odd->odd or even->even */
  2381.  
  2382.             if (upwards) {
  2383.  
  2384.                 src = p->bitplane + sy * linesize + (sx>>1)*16 + (sx & 1);
  2385.                 dst = p->bitplane + dy * linesize + (dx>>1)*16 + (dx & 1);
  2386.  
  2387.                 if (sx & 1) {
  2388.                     memmove_8p_col( dst, src, colsize, bytes );
  2389.                     src += 15;
  2390.                     dst += 15;
  2391.                     --width;
  2392.                 }
  2393.  
  2394.                 if (width > 1) {
  2395.                     for( rows = colsize; rows > 0; --rows ) {
  2396.                         mymemmove( dst, src, (width>>1)*16 );
  2397.                         src += bytes;
  2398.                         dst += bytes;
  2399.                     }
  2400.                 }
  2401.                 
  2402.                 if (width & 1) {
  2403.                     src -= colsize * bytes;
  2404.                     dst -= colsize * bytes;
  2405.                     memmove_8p_col( dst + (width>>1)*16, src + (width>>1)*16,
  2406.                                     colsize, bytes );
  2407.                 }
  2408.             }
  2409.             else {
  2410.  
  2411.                 if (!((sx+width-1) & 1)) {
  2412.                     src = p->bitplane + sy * linesize + ((sx+width-1)>>1)*16;
  2413.                     dst = p->bitplane + dy * linesize + ((dx+width-1)>>1)*16;
  2414.                     memmove_8p_col( dst, src, colsize, bytes );
  2415.                     --width;
  2416.                 }
  2417.  
  2418.                 src = p->bitplane + sy * linesize + (sx>>1)*16 + (sx & 1);
  2419.                 dst = p->bitplane + dy * linesize + (dx>>1)*16 + (dx & 1);
  2420.  
  2421.                 if (width > 1) {
  2422.                     src += colsize * bytes + (sx & 1)*15;
  2423.                     dst += colsize * bytes + (sx & 1)*15;
  2424.                     for( rows = colsize; rows > 0; --rows ) {
  2425.                         src -= bytes;
  2426.                         dst -= bytes;
  2427.                         mymemmove( dst, src, (width>>1)*16 );
  2428.                     }
  2429.                 }
  2430.  
  2431.                 if (width & 1) {
  2432.                     memmove_8p_col( dst-15, src-15, colsize, bytes );
  2433.                 }
  2434.  
  2435.             }
  2436.         }
  2437.         else {
  2438.             /* odd->even or even->odd */
  2439.  
  2440.             if (upwards) {
  2441.                 src = p->bitplane + sy * linesize + (sx>>1)*16 + (sx & 1);
  2442.                 dst = p->bitplane + dy * linesize + (dx>>1)*16 + (dx & 1);
  2443.                 for( cols = width; cols > 0; --cols ) {
  2444.                     memmove_8p_col( dst, src, colsize, bytes );
  2445.                     INC_8P( src );
  2446.                     INC_8P( dst );
  2447.                 }
  2448.             }
  2449.             else {
  2450.                 sx += width-1;
  2451.                 dx += width-1;
  2452.                 src = p->bitplane + sy * linesize + (sx>>1)*16 + (sx & 1);
  2453.                 dst = p->bitplane + dy * linesize + (dx>>1)*16 + (dx & 1);
  2454.                 for( cols = width; cols > 0; --cols ) {
  2455.                     memmove_8p_col( dst, src, colsize, bytes );
  2456.                     DEC_8P( src );
  2457.                     DEC_8P( dst );
  2458.                 }
  2459.             }
  2460.         }
  2461.             
  2462.         
  2463.     }
  2464. }
  2465.  
  2466.  
  2467. static void atacon_clear_8_plane( struct condata *conp, register struct
  2468.                                   display *p, int sy, int sx, int height,
  2469.                                   int width )
  2470. {
  2471.     ulong offset;
  2472.     register u_char *start;
  2473.     register ushort rows;
  2474.     register ushort bytes = p->bytes_per_row;
  2475.     ushort          lines = height * p->fontheight;
  2476.     register ulong  size;
  2477.     u_long          cval1, cval2, cval3, cval4, pcval1, pcval2;
  2478.  
  2479.     expand8ql( (conp->vc_video_erase_char >> 12) & 0xf,
  2480.                &cval1, &cval2, &cval3, &cval4 );
  2481.     
  2482.     if (sx == 0 && width == bytes/8) {
  2483.  
  2484.         offset = sy * bytes * p->fontheight;
  2485.         size   = lines * bytes;
  2486.         memset_even_8p( p->bitplane+offset, size, cval1, cval2, cval3, cval4 );
  2487.  
  2488.     } else {
  2489.  
  2490.         offset = (sy * bytes * p->fontheight) + (sx>>1)*16 + (sx & 1);
  2491.         start = p->bitplane + offset;
  2492.         expand8dl( (conp->vc_video_erase_char >> 12) & 0xf, &pcval1, &pcval2 );
  2493.         
  2494.         /* Clears are split if the region starts at an odd column or
  2495.          * end at an even column. These extra columns are spread
  2496.          * across the interleaved planes. All in between can be
  2497.          * cleared by normal mymemclear_small(), because both bytes of
  2498.          * the single plane words are affected.
  2499.          */
  2500.  
  2501.         if (sx & 1) {
  2502.             memclear_8p_col( start, lines, pcval1, pcval2, bytes );
  2503.             start += 7;
  2504.             width--;
  2505.         }
  2506.  
  2507.         if (width & 1) {
  2508.             memclear_8p_col( start + (width>>1)*16, lines, pcval1,
  2509.                              pcval2, bytes );
  2510.             width--;
  2511.         }
  2512.  
  2513.         if (width) {
  2514.             for( rows = lines; rows-- ; start += bytes )
  2515.                 memset_even_8p( start, width*8, cval1, cval2, cval3, cval4 );
  2516.         }
  2517.     }
  2518. }
  2519.  
  2520.  
  2521. static void atacon_putc_8_plane( struct condata *conp, struct display *p,
  2522.                                  int c, int y, int x, int mode)
  2523. {    register u_char   *dest;
  2524.     register u_char   *cdat;
  2525.     register ushort   rows;
  2526.     register u_short  bytes = p->bytes_per_row;
  2527.     ulong              eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
  2528.  
  2529.     if (!FONT_CNV(c)) return;
  2530.  
  2531.     dest  = p->bitplane + y * p->fontheight * bytes + (x>>1)*16 + (x & 1);
  2532.     cdat  = p->fontdata + (c * p->fontheight);
  2533.  
  2534.     expand8dl( conp->vc_attr & 0x0f, &fgx1, &fgx2 );
  2535.     expand8dl( (conp->vc_attr >> 4) & 0x0f, &bgx1, &bgx2 );
  2536.     eorx1  = fgx1 ^ bgx1; eorx2  = fgx2 ^ bgx2;
  2537.         
  2538.     for( rows = p->fontheight ; rows-- ; dest += bytes ) {
  2539.         fdx = dup4l( *cdat++ );
  2540.         __asm__ __volatile__
  2541.             ( "movepl %1,%0@(0)\n\t"
  2542.               "movepl %2,%0@(8)"
  2543.               : /* no outputs */
  2544.               : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
  2545.                 "d" ((fdx & eorx2) ^ bgx2)
  2546.             );
  2547.     }
  2548.  
  2549.     if (conp->vc_underline) {
  2550.         __asm__ __volatile__
  2551.             ( "movepl %1,%0@(0)\n\t"
  2552.               "movepl %2,%0@(8)"
  2553.               : /* no outputs */
  2554.               : "a" (dest-bytes), "d" (fgx1), "d" (fgx2)
  2555.             );
  2556.     }
  2557. }
  2558.  
  2559.  
  2560. static void atacon_putcs_8_plane( struct condata *conp, struct
  2561.                                   display *p, const char *s,
  2562.                                   int count, int y, int x, int mode)
  2563.  
  2564. {    register u_char   *dest, *dest0;
  2565.     register u_char   *cdat, c;
  2566.     register ushort   rows;
  2567.     register u_short  bytes;
  2568.     ulong              eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
  2569.  
  2570.     bytes = p->bytes_per_row;
  2571.     dest0 = p->bitplane + y * p->fontheight * bytes + (x>>1)*16 + (x & 1);
  2572.  
  2573.     expand8dl( conp->vc_attr & 0x0f, &fgx1, &fgx2 );
  2574.     expand8dl( (conp->vc_attr >> 4) & 0x0f, &bgx1, &bgx2 );
  2575.     eorx1  = fgx1 ^ bgx1; eorx2  = fgx2 ^ bgx2;
  2576.  
  2577.     while( count-- > 0 ) {
  2578.  
  2579.         /* I think, unrolling the loops like in the 1 plane case isn't
  2580.          * practicable here, because the body is much longer for 4
  2581.          * planes (mostly the dup4l()). I guess, unrolling this would
  2582.          * need more than 256 bytes and so exceed the instruction
  2583.          * cache :-(
  2584.          */
  2585.         
  2586.         c = *s++;
  2587.         if (!FONT_CNV(c)) continue;
  2588.         cdat  = p->fontdata + (c * p->fontheight);
  2589.     
  2590.         for( rows = p->fontheight, dest = dest0; rows-- ; dest += bytes ) {
  2591.             fdx = dup4l( *cdat++ );
  2592.             __asm__ __volatile__
  2593.                 ( "movepl %1,%0@(0)\n\t"
  2594.                   "movepl %2,%0@(8)"
  2595.                   : /* no outputs */
  2596.                   : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
  2597.                   "d" ((fdx & eorx2) ^ bgx2)
  2598.                 );
  2599.         }
  2600.  
  2601.         if (conp->vc_underline) {
  2602.             __asm__ __volatile__
  2603.                 ( "movepl %1,%0@(0)\n\t"
  2604.                   "movepl %2,%0@(8)"
  2605.                   : /* no outputs */
  2606.                   : "a" (dest-bytes), "d" (fgx1), "d" (fgx2)
  2607.                 );
  2608.         }
  2609.  
  2610.         INC_8P(dest0);
  2611.     }
  2612. }
  2613.  
  2614.  
  2615. static void atacon_rev_char_8_plane( struct display *display, int x, int y )
  2616.  
  2617. {    u_char    *p;
  2618.     u_short j;
  2619.     
  2620.     p = display->bitplane +
  2621.         y * display->fontheight * display->bytes_per_row +
  2622.         (x>>1)*16 + (x & 1);
  2623.     j = display->fontheight - 1;
  2624.  
  2625.     __asm__ __volatile__
  2626.         /* This should really obey the individual character's
  2627.          * background and foreground colors instead of simply
  2628.          * inverting. For 8 plane mode, only the lower 4 bits of the
  2629.          * color are inverted, because only that color registers have
  2630.          * been set up.
  2631.          */
  2632.         ("1: notb  %0@ ; notb %0@(2) ; notb %0@(4) ; notb %0@(6)\n\t"
  2633.          "addaw %4,%0\n\t"
  2634.          "dbra  %1,1b"
  2635.          : "=a" (p), "=d" (j)
  2636.          : "0" (p), "1" (j), "d" (display->bytes_per_row)
  2637.          );
  2638. }
  2639.  
  2640.  
  2641. #endif /* CONFIG_ATARI_8PLANE */
  2642.  
  2643.  
  2644. /* ================================================================= */
  2645. /*                            Cursor Functions                       */
  2646. /* ================================================================= */
  2647.  
  2648.  
  2649. #ifdef CURSOR_DELAY_TIMER
  2650.  
  2651. static void atacon_curtimfunc( unsigned long _disp )
  2652.  
  2653. {    struct display *display = (struct display *)_disp;
  2654.  
  2655.     /* Do nothing if cursor is already drawn (how?) or the active
  2656.      * console has been changed.
  2657.      */
  2658.     if (cursor_drawn || display != &disp[fg_console])
  2659.         return;
  2660.  
  2661.     atacon_rev_char( display, display->cursor_x, display->cursor_y );
  2662.     cursor_drawn = 1;
  2663.  
  2664. }
  2665.  
  2666. #endif
  2667.  
  2668. #ifdef CURSOR_DELAY_VBL
  2669.  
  2670. static void atacon_vbl_handler( struct intframe *fp, void *dummy )
  2671.  
  2672. {    struct display *display;
  2673.  
  2674.     if (!cursor_on) return;
  2675.     
  2676.     if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
  2677.         /* Here no check is possible for console changing. The console
  2678.          * switching code should set vbl_cursor_cnt to an appropriate value.
  2679.          */
  2680.         display = &disp[fg_console];
  2681.         display->dispsw->rev_char( display, display->cursor_x,
  2682.                                    display->cursor_y );
  2683.         cursor_drawn ^= 1;
  2684.         vbl_cursor_cnt = cursor_blink_rate;
  2685.     }
  2686. }
  2687.  
  2688. #endif
  2689.  
  2690.  
  2691. static int atacon_cursor (struct condata *conp, int mode)
  2692.  
  2693. {    struct display *display = &disp[conp - vc_cons];
  2694.  
  2695.     switch( mode ) {
  2696.  
  2697.       case CM_ERASE:
  2698.         if (cursor_drawn)
  2699.             display->dispsw->rev_char( display, display->cursor_x,
  2700.                                        display->cursor_y );
  2701.         display->cursor_x = conp->vc_x;
  2702.         display->cursor_y = conp->vc_y;
  2703.         CURSOR_UNDRAWN();
  2704. #ifdef CURSOR_DELAY_VBL
  2705.         cursor_on = 0;
  2706. #endif
  2707.         break;
  2708.  
  2709.       case CM_MOVE:
  2710.       case CM_DRAW:
  2711.         if (cursor_drawn)
  2712.             display->dispsw->rev_char( display, display->cursor_x,
  2713.                                        display->cursor_y);
  2714.         CURSOR_UNDRAWN();
  2715.  
  2716.         display->cursor_x = conp->vc_x;
  2717.         display->cursor_y = conp->vc_y;
  2718.  
  2719. #ifdef CURSOR_DELAY_TIMER        
  2720.         del_timer( &atacon_cursor_timer );
  2721.         atacon_cursor_timer.expires = CURSOR_DRAW_DELAY;
  2722.         atacon_cursor_timer.data = (unsigned long)display;
  2723.         add_timer( &atacon_cursor_timer );
  2724. #endif
  2725. #ifdef CURSOR_DELAY_VBL
  2726.         vbl_cursor_cnt = CURSOR_DRAW_DELAY;
  2727.         cursor_on = 1;
  2728. #endif
  2729.         break;
  2730.     }
  2731.  
  2732.     return( 0 );
  2733. }
  2734.  
  2735. /*
  2736.  * The console "switch" structure for the Atari native console
  2737.  */
  2738.  
  2739.  
  2740. struct consw ata_con =
  2741. {
  2742.     atacon_init, atacon_deinit, atacon_clear, atacon_putc, atacon_putcs,
  2743.     atacon_cursor, atacon_scroll, atacon_bmove, atacon_switch
  2744. };
  2745.  
  2746.